測試1:openSession在不開啟事務(wù)的情況下執(zhí)行操作
Session session= SessionFactoryUtil.openSession();
(1):session.get(UserInfo.class,14L); //執(zhí)行成功,得到數(shù)據(jù)
(2):session.delete(new UserInfo(16L)); //執(zhí)行成功 但數(shù)據(jù)庫數(shù)據(jù)不變(符合邏輯)
session.close();
追溯了下源碼發(fā)現(xiàn):
在不開啟事務(wù)的情況下,session得到數(shù)據(jù)庫連接是在執(zhí)行查詢語句的時(shí)候從連接池中獲得。
private PreparedStatement getPreparedStatement(
final Connection conn,
String sql,
boolean scrollable,
final boolean useGetGeneratedKeys,
final String[] namedGeneratedKeys,
final ScrollMode scrollMode,
final boolean callable) ;在調(diào)用這個(gè)方法時(shí)傳入了從連接池中拿到的連接。
在執(zhí)行完數(shù)據(jù)操作后調(diào)用
afterOperation(boolean success);
發(fā)現(xiàn)是非事務(wù)型的session直接調(diào)用
connectionManager.aggressiveRelease();
釋放連接。
測試2:getCurrentSession()在不開啟事務(wù)的情況下執(zhí)行操作
Session session= SessionFactoryUtil.getCurrentSession();
(1):session.get(UserInfo.class,14L); //拋出異常get is not valid without active transaction
(2):session.delete(new UserInfo(16L));// 拋出異常get is not valid without active transaction
//session.close(); //線程綁定session會自動關(guān)閉
說明: 線程綁定session必須開啟事務(wù),此時(shí)的session已經(jīng)加載了攔截器,在執(zhí)行數(shù)據(jù)操作時(shí)必須在活動的事務(wù)范圍中。
測試3:openSession在開啟事務(wù)的情況下執(zhí)行操作
Session session= SessionFactoryUtil.openSession();
session.getTransaction().begin();
(1):session.get(UserInfo.class,14L); //執(zhí)行成功,得到數(shù)據(jù)
(2):session.delete(new UserInfo(16L)); //執(zhí)行成功
session.getTransaction().commit();
session.close(); //如若配置hibernate.transaction.auto_close_session=true可省去
分析:
(a):session.getTransaction().begin()-->Transaction result = getTransaction()
-->result.begin()-->jdbcContext.connection()
{
if ( owner.isClosed() ) {
throw new SessionException( "Session is closed" );
}
return connectionManager.getConnection();
}
見到connectionManager有點(diǎn)熟悉了吧,這就是管理數(shù)據(jù)庫連接的連接池.
(b):session.getTransaction().commit()-->connectionManager.aggressiveRelease() 釋放連接。
此時(shí)的數(shù)據(jù)庫連接是在準(zhǔn)備開啟事務(wù)的時(shí)獲得,事務(wù)提交的時(shí)候釋放連接。
測試4:getCurrentSession()在開啟事務(wù)的情況下執(zhí)行操作
Session session= SessionFactoryUtil.getCurrentSession();
session.getTransaction().begin();
(1):session.get(UserInfo.class,14L); //執(zhí)行成功
(2):session.delete(new UserInfo(16L)); //執(zhí)行成功
session.getTransaction().commit();
說明: 線程綁定session已經(jīng)加載了攔截器,提交的時(shí)候釋放連接關(guān)閉session。
總結(jié):
(1)openSession()得到得session可以在顯式開啟事務(wù)的環(huán)境中使用,也可以在不開啟事務(wù)的環(huán)境中使用(進(jìn)行查詢);getCurrentSession()必須在顯式開啟事務(wù)環(huán)境中使用。
(2)openSession()是否顯式開啟事務(wù)決定了session得到連接的時(shí)機(jī)不同。不開啟事務(wù)的情況下數(shù)據(jù)庫連接是在創(chuàng)建Statement時(shí)獲得。因此在配置二級緩存的情況get()對象時(shí),如果二級緩存中有需要的對象時(shí),不會占用數(shù)據(jù)庫連接。相反開啟事務(wù)的情況下,無論二級緩存中是否有對象,多會占用數(shù)據(jù)庫連接。
(3)getCurrentSession()總會占用數(shù)據(jù)庫連接。
以上是學(xué)習(xí)Hibernate時(shí)的一些想法,不知道寫得對不對。請大家指正。
******************************
SessionFactory.getCurrentSession與openSession的區(qū)別
1. 如果使用的是getCurrentSession來創(chuàng)建session的話,在commit后,session就自動被關(guān)閉了,
也就是不用再session.close()了。但是如果使用的是openSession方法創(chuàng)建的session的話,
那么必須顯示的關(guān)閉session,也就是調(diào)用session.close()方法。這樣commit后,session并沒有關(guān)閉
2. getCurrentSession的使用可以參見hibernate\hibernate-3.2\doc\tutorial\src項(xiàng)目
3. 使用SessionFactory.getCurrentSession()需要在hibernate.cfg.xml中如下配置:
* 如果采用jdbc獨(dú)立引用程序配置如下:
<property name="hibernate.current_session_context_class">thread</property>
* 如果采用了JTA事務(wù)配置如下
<property name="hibernate.current_session_context_class">jta</property>