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