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()。

發佈了150 篇原創文章 · 獲贊 119 · 訪問量 73萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章