1. 程式人生 > >Hibernate Session和Jpa EntityManager

Hibernate Session和Jpa EntityManager

本文主要比較一下二者操作實體類的方法的關係和區別。

本文適用 Hibernate:4.3.11.Final 和 spring-data-jpa:1.10.4.RELEASE 。

建立方式

Session:

Configuration configuration=new Configuration().configuration();

ServiceRegistry serviceRegistry=new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();

SessionFactory sessionFactory=configuration.buildSessionFactory(serviceRegistry);

Session session=factory.openSession();

Transaction transaction=session.beginTransaction();
//to do sth.
transaction.commit(); session.cose(); sessionFactory.close();

EntityManager:

EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("persistenceUnitName");

EntityManager entityManager=entityManagerFactory.createEntityManager();

EntityTransaction entityTransaction=entityManager.createEntityTransaction();
entityTransaction.begin();
//to do sth.
entityTransaction.commit(); entityManager.close(); entityManagerFactory.close();

二者的聯絡

SessionFactory 對應 EntityManagerFactory;

Session 對應 EntityManager;

SessionFactory是執行緒安全的,Session不是執行緒安全的;

EntityManager 是執行緒安全的;

關於配置檔案

Hibernate需要一個配置檔案:hibernate.xml,檔案在classpath可以訪問即可。

JPA需要一個persistence.xml,檔案必須是META/persistence.xml

如果整合Spring的話,就讓他們隨風去吧。

方法對比

session的方法:

flush()
evict()
load()
save()
saveOrUpdate()
update()
merge()
persist()
delete()
refresh()
get()

EntityManager的方法:

persist()
merge()
remove()
find()
flush()
refresh()
detach()
getReference()

從上面看出,jpa操作實體類的方法少了很多。

為了看起來不太混亂,以下用S代替Session,E代替EntityManager.

S.evict() = E.detach()

二者對應。

S.load() = E.getReference()

執行查詢時返回代理物件,這是懶載入。spring-data-jpa中對應getOne();

如果資料庫中沒有對應的記錄,拋異常。

注:這裡spring-data-jpa又任性了,getOne()不是對應get(),注意。還有更任性的,如果物件在快取中的話,那麼getOne就會返回實體物件,否則返回代理物件。

S.get() = E.find()

執行查詢時返回實體物件,立即載入。spring-data-jpa中對應findOne();

如果資料庫中沒有對應的記錄,則返回null。

S.persist() = E.persist()

二者對應。

S.save() ≈ E.persist()

EntityManager沒有save方法。

區別:

呼叫前的實體物件,如果主鍵使用setter設定了值,E.persist()會拋異常。而S.save()不會拋異常,只是會忽略。

S.delete() ≈ E.remove()

區別:delete()可以移出持久化物件和遊離物件,而remove只能移出持久化物件,否則會拋異常。

S.saveOrUpdate()+S.merge() ≈ E.merge()

E.merge()當實體物件O1為臨時物件,會建立一個新物件O2,執行insert操作,並返回這個新物件,相當於S.saveOrUpdate()。此時O2為持久化物件,而O1仍然是遊離物件。

E.merge()當實體物件O1位遊離物件,即主鍵不為空:
首先查詢快取中是否有該主鍵對應的持久化物件,如果有,將快取中的物件提取為O2,然後根據O1的值修改O2,並對O2執行update,返回O2.

如果快取中不存在,那麼就傳送一條select去查詢資料庫中是否有持久化物件,如果存在,查詢返回的持久化物件O2,根據O1修改O2的屬性,並對O2執行update;否則,新建一個臨時物件O2,複製O1的屬性,並對O2執行insert,返回O2。

以上E.merge()類似於S.saveOrUpdate(),下面看一下Hibernate中的一種情況:

@Test
@org.springframework.transaction.annotation.Transactional
public void testHibernate(){
  Session session=sessionFactory.getCurrentSession();
  Transaction transaction = session.beginTransaction();
  User u1=(User) session.get(User.class, 1);
  User u2=new User();
  u2.setId(1);
  session.saveOrUpdate(u2);
  System.out.println(u1==u2);
  transaction.commit();
  session.close();
}

Hibernate不允許快取中存在兩個持久化物件對應同一個主鍵。

而JPA中不拋異常:

@Test
@Transactional
public void testJpa(){
  User u1=entityManager.find(User.class, 1);
  User u2=new User();
  u2.setId(1);
  u2.setUserName("Jack");
  User u3=entityManager.merge(u2);
  System.out.println(Arrays.asList(u1));
  System.out.println(Arrays.asList(u2));
  System.out.println(u1==u2);
  System.out.println(u1==u3);
}

這是由於JPA不是在快取中載入了第二個同一主鍵的實體物件,而是進行了實體物件的拷貝。

再看S.merge():

@Test
@org.springframework.transaction.annotation.Transactional
public void testHibernateMerge(){
  Session session=sessionFactory.getCurrentSession();
  Transaction transaction = session.beginTransaction();
  User u1=(User) session.get(User.class, 1);
  User u2=new User();
  u2.setId(1);
  User u3=(User) session.merge(u2);
  System.out.println(u1==u2);
  System.out.println(u1==u3);
  transaction.commit();
  session.close();
}

這樣是可以的,也就是說在這種情況下,S.merge()=E.merge()。