測試1:openSession在不開啟事務的情況下執行操作

  Session session= SessionFactoryUtil.openSession();

  (1):session.get(UserInfo.class,14L);  //執行成功,得到數據

  (2):session.delete(new UserInfo(16L));  //執行成功 但數據庫數據不變(符合邏輯)

  session.close();

  追溯了下源碼發現:

  在不開啟事務的情況下,session得到數據庫連接是在執行查詢語句的時候從連接池中獲得。

Java代碼
  1. private PreparedStatement getPreparedStatement(  
  2.             final Connection conn,  
  3.             String sql,  
  4.             boolean scrollable,  
  5.             final boolean useGetGeneratedKeys,  
  6.             final String[] namedGeneratedKeys,  
  7.             final ScrollMode scrollMode,  
  8.             final boolean callable)   

      在調用這個方法時傳入了從連接池中拿到的連接。

  在執行完數據操作后調用

  afterOperation(boolean success);

  發現是非事務型的session直接調用

  connectionManager.aggressiveRelease();

  釋放連接。

  測試2:getCurrentSession()在不開啟事務的情況下執行操作

  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會自動關閉

  說明: 線程綁定session必須開啟事務,此時的session已經加載了攔截器,在執行數據操作時必須在活動的事務范圍中。

  測試3:openSession在開啟事務的情況下執行操作

  Session session= SessionFactoryUtil.openSession();

  session.getTransaction().begin();

  (1):session.get(UserInfo.class,14L);  //執行成功,得到數據

  (2):session.delete(new UserInfo(16L));  //執行成功

  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有點熟悉了吧,這就是管理數據庫連接的連接池.

  (b):session.getTransaction().commit()-->connectionManager.aggressiveRelease() 釋放連接。

  此時的數據庫連接是在準備開啟事務的時獲得,事務提交的時候釋放連接。

  測試4:getCurrentSession()在開啟事務的情況下執行操作

  Session session= SessionFactoryUtil.getCurrentSession();

  session.getTransaction().begin();

  (1):session.get(UserInfo.class,14L);        //執行成功

  (2):session.delete(new UserInfo(16L));   //執行成功

  session.getTransaction().commit();

  說明: 線程綁定session已經加載了攔截器,提交的時候釋放連接關閉session。

  總結:

  (1)openSession()得到得session可以在顯式開啟事務的環境中使用,也可以在不開啟事務的環境中使用(進行查詢);getCurrentSession()必須在顯式開啟事務環境中使用。

  (2)openSession()是否顯式開啟事務決定了session得到連接的時機不同。不開啟事務的情況下數據庫連接是在創建Statement時獲得。因此在配置二級緩存的情況get()對象時,如果二級緩存中有需要的對象時,不會占用數據庫連接。相反開啟事務的情況下,無論二級緩存中是否有對象,多會占用數據庫連接。

  (3)getCurrentSession()總會占用數據庫連接。

除非特別注明,雞啄米文章均為原創
轉載請標明本文地址:http://www.ojizl5.fun/software/754.html
2017年8月17日
作者:雞啄米 分類:軟件開發 瀏覽: 評論:0