2 Aralık 2018 Pazar

JPA EntityManager Arayüzü

Giriş
Şu satırı dahil ederiz.
import javax.persistence.EntityManager;
Bu sınıfı EntityManagerFactory tarafından yaratılır. Açıklaması şöyle.
In general you need a single Entity Manager per transaction. And this Entity Manager must not be used in two transactions at the same time.
Bu sınıf @PersistenceContext Anotasyonu tarafından inject edilebilir.

Hibernate bu arayüzü HibernateEntityManager sınıfı ile gerçekleştirir.

Bu sınıf checked exception fırlatmaz. PersistenceException'dan kalıtan bir unchecked exception fırlatır.

Örnek
Şöyle yaparız.
EntityManager em = createEntityManager();

try {

    em.getTransaction().begin();
    // Do something with the EntityManager such as persist(), merge() or remove()
    em.getTransaction().commit();
} catch(Exception e) {

    em.getTransaction().rollback();
}

em.close();
constructor
Şöyle yaparız.
EntityManagerFactory emf = ...;
EntityManager em = emf.createEntityManager();
clear metodu
Belleği temizlediği için uygulamayı hızlandırabilir.

close metodu
Şöyle yaparız.
em.close();
createNamedQuery metodu
JPQL veya native SQL kullanabilir. Bir Query nesnesi döner. Sorgu cümlesine isim ile erişiriz. Şöyle yaparız.
Query q = em.createNamedQuery("Card.findPrefix");
createNativeQuery metodu
SQL kullanan bir Query nesnesi döner. Şöyle yaparız.
Query q = em.createNativeQuery("select count(*) from your_table_name")
createQuery metodu - CriteriaQuery
JPQL kullanır. CriteriaQuery<T> nesnesi olduğu için TypedQuery döndürür.
Örnek
Şöyle yaparız.
CriteriaQuery<UserDTO> cq = ...;
...
TypedQuery<UserDTO> query = em.createQuery(cq);
Örnek
Şöyle yaparız.
CriteriaQuery<Long> sc = ...;
...
Long count = em.createQuery(sc).getSingleResult();
createQuery metodu - String
JPQL kullanır. Bir Query nesnesi döner. Dışarından alınacak parametreler ":" karakteri ile başlayan değişkenlerle belirlenir. Bu değişkenlere değerleri setParameter() metodu ile atanır.
Örnek
Şöyle yaparız.
Query q = em.createQuery("SELECT s FROM Status s WHERE s.statusName =:status");
Örnek
Şöyle yaparız.
em.createQuery("select gne from Entity gne where type(gne) = :subclass")
  .setParameter("subclass", GivenNameEntity.class)
  .getResultList();
Örnek
Şöyle yaparız.
String sql = "select r from Rent r JOIN FETCH r.rentables where r.id = :rid";
Query queryString =  em.createQuery(sql)
    .setParameter("rid", rent.getId());
List<Rent> resultList = queryString.getResultList();
createQuery metodu - String + Class
İkinci parametre T tipi olduğu için TypedQuery döndürür.TypedQuery yazısına taşıdım.

createStoredProcedureQuery metodu
StoredProcedureQuery nesnesi yaratır.
Örnek
Şöyle yaparız
StoredProcedureQuery sp = em.createStoredProcedureQuery(procName);
detach metodu
Örnek ver

find metodu
EntityManager.find() metodu nesneyi aynı Hibernate'in Session.find() metodunda olduğu gibi hemen yükler. EntityManager.getReference() ise Hibernate'in Session.load() metodunda olduğu gibi hemen yüklemez bir proxy nesnesi döner.

Örnek
Şöyle yaparız.
Foo foo = em.find(Foo.class, fooId);
Örnek
find metodu önce kendi önbelleği (cache) içinde arama yapar. Her EntityManager nesnesinin kendi önbelleği vardır. Bunu görmek için şöyle yaparız. em1 içinde yaratılan nesne önbellekte saklanır. em2 içinde güncellense bile em1'in haberi olmaz. em1 nesneye tekrar erişmek isterse eski bilgisi ile önbellekten getirir.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");

// Step 1: create entity
EntityManager em1 = emf.createEntityManager();
em1.getTransaction().begin();
Article article = new Article("article_1");
em1.persist(article);
em1.getTransaction().commit();

// Step 2: update entity
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();
Article articleForUpdate = em2.find(Article.class, 1L);
articleForUpdate.setName("updated article_1");
em2.persist(articleForUpdate);
em2.getTransaction().commit();

// Step 3: read updated entity
em1.getTransaction().begin();
Article updatedArticle = em1.find(Article.class, 1L);
em1.getTransaction().commit();

log.info("updated entity: {}", updatedArticle); // logs stale data

em1.close();
em2.close();
emf.close();

Örnek
find ve getReference farkı şöyle
// will return the persistent instance and never returns an uninitialized instance
em.find(Owner.class, id);

// might return a proxied instance that is initialized on-demand
em.getReference(Owner.class, id);
Benzer mantık Hibernate Session sınıfında da var.
// will return the persistent instance and never returns an uninitialized instance
session.get(Owner.class, id);

// might return a proxied instance that is initialized on-demand
session.load(Owner.class, id);
flush metodu
Şöyle yaparız.
em.flush();
getCriteriaBuilder metodu
Şöyle yaparız.
CriteriaBuilder cb = em.getCriteriaBuilder();
getEntityManagerFactory metodu
EntityManagerFactory nesnesi döner. Şöyle yaparız.
entityManager.getEntityManagerFactory().getCache().evictAll()
getReference metodu
EntityManager.find() metodu nesneyi aynı Hibernate'in Session.find() metodunda olduğu gibi hemen yükler. EntityManager.getReference() ise Hibernate'in Session.load() metodunda olduğu gibi hemen yüklemez bir proxy nesnesi döner. Hibernate'in açıklaması şöyle
getReference() obtains a reference to the entity. The state may or may not be initialized. If the entity is already associated with the current running Session, that reference (loaded or not) is returned. If the entity is not loaded in the current Session and the entity supports proxy generation, an uninitialized proxy is generated and returned, otherwise the entity is loaded from the database and returned.
getTransaction metodu
EntityTransaction nesnesi döner. Şöyle yaparız.
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();

em.persist(...);
em.persist(...);
em.persist(...);

em.getTransaction().commit();
joinTransaction metodu
Açıklaması şöyle
The purpose of entityManager.joinTransaction(); is to notify the persistence context to synchronize itself with the current transaction.
Şöyle yaparız.
em.joinTransaction();
lock metodu
Optimistic lock kullanırken veritabanı seviyesinde gerçek bir kilit kullanılmaz!

OPTIMISTIC
Bu seçenek için iyi bir örnek bulamadım. Açıklaması şöyle. Yani biz veritabanını en son kontrol ettiğimizde halen geçerli sürüm varsa, yazma işlemi sonlandırılır. Tabi bu halen yazma işleminin başarılı olacağı anlamına gelmez.
This type of lock will guarantee that the entity will not be changed by some other process while the current transaction is in progress, and is to be used in entities that we will only read but require that no other process change the entity until our transaction completes. Remember that we are still talking about optimistic locking, so other transactions may actually change the locked record, but our transaction will fail as soon as it detects that those changes took place.
...
Note that it's still possible for another transaction to change the record between this last SELECT statement check and the final commit, but in terms of business logic it's no longer relevant. What matters is that when we checked the version after doing all the work, the record was still unchanged, so any work that depends on that record being unchanged may be considered as correct because we guaranteed that we used an unchanged entity during all the unit of work duration.
OPTIMISTIC_FORCE_INCREMENT
Bu seçenek için iyi bir örnek bulamadım. Açıklaması şöyle.
This locking mode guarantees that the version field will also be incremented even in the case of optimistic locking read operations. Write operations do not apply here because the version field is always incremented in write operations.
PESSIMISTIC_WRITE
Açıklaması şöyle. Ben yazma yaparken başkası ne yazabilir ne de okuyabilir.
This instruction will be translated into a SELECT ... FOR UPDATE statement:
Veritabanı seviyesinde satır için kilit atar. Açıklaması şöyle.
The record will become locked for the duration of the current transaction. Any UPDATE operation, SELECT ... FOR UPDATE operation, or pessimistic READ lock operation executed against that same record by other transaction will become locked at the database level until the current transaction - that holds the lock - completes. The semantics are similar to an exclusive write lock.
Şöyle yaparız.
MyEntity e = repo.findByName(name)
              .orElseThrow(() -> new ResourceNotFoundException(name));
try {
    em.lock(e, LockModeType.PESSIMISTIC_WRITE)
} catch ( PessimisticLockException e) {
    //Handle somehow
}
repo.delete(e);
PESSIMISTIC_READ
Açıklaması şöyle. Ben okuma yaparken başkası da okuyabilir ancak ben başkasının yazmasını engellerim.
The pessimistic lock for read operations is only available in some database systems. When this strategy is not available for the current database, the JPA provider will issue a pessimistic write lock instead.
This operation will lock the record in a shared mode, meaning that other transactions may freely read the record and even lock that same record using an identical pessimist read strategy and still continue to process. Every write operation or write lock against the record will become locked by the database until no other transaction holds a lock to that record. Such write operations that are locked by the database while a transaction holds a read lock include UPDATE operations and SELECT ... FOR UPDATE operations. The semantics are similar to a shared read lock.
PESSIMISTIC_FORCE_INCREMENT 
Açıklaması şöyle.
This lock mode will result in a pessimistic write lock (SELECT ... FOR UPDATE) and will make sure that an eventually existing entity version field is incremented, even if the entity being locked is not changed by the current transaction which acquired the lock.
merge metodu
Açıklaması şöyle.
When merge()is invoked on a new entity, it behaves similarly to the persist()operation. It adds the entity to the persistence context, but instead of adding the original entity instance, it creates a new copy and manages that instance instead. The copy that is created by the merge()operation is persisted as if the persist()method were invoked on it.
OneToMany ilişikilerde CascadeType = MERGE ise yeni bir child eklenirse, yeni nesneyi kaydeder ve sonuç olarak döner.
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped withcascade="merge".
persist metodu
@Entity olarak işaretli bir nesnesi veritabanına kaydeder. Şöyle yaparız. Eğer entity veritabanında varsa EntityExistsException fırlatılır. Açıklaması şöyle.
Thrown by the persistence provider when EntityManager.persist(Object) is called and the entity already exists
em.getTransaction().begin();
  Foo foo = new  Foo(...);
  em.persist(k);
em.getTransaction().commit();
refresh metodu
Şöyle yaparız.
SomeEntity someEntity = ...;// this entity was found by entity manager previously

em.refresh(someEntity);
unwrap metodu
Açıklaması şöyle.
Since version 2.0, JPA provides easy access to the APIs of the underlying implementations. EntityManager and EntityManagerFactory provide an unwrap method, which returns the corresponding classes of the JPA implementation. In Hibernate’s case, Session and SessionFactory give you full access to proprietary Hibernate features, such as the support for Streams and Optional.
Şu satırı dahil ederiz.
import org.hibernate.Session;
Şöyle yaparız.
Session session = em.unwrap(Session.class);



Hiç yorum yok:

Yorum Gönder