1. 程式人生 > >Hibernate事務操作及session與本地執行緒繫結

Hibernate事務操作及session與本地執行緒繫結

事務相關概念

  1 什麼是事務

    事務是應用程式中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。也就是事務具有原子性,一個事務中的一系列的操作要麼全部成功,要麼一個都不做。 
    事務的結束有兩種,當事務中的所以步驟全部成功執行時,事務提交。如果其中一個步驟失敗,將發生回滾操作,撤消撤消之前到事務開始時的所以操作。

 

  2 事務特性

     事務具有四個特徵:原子性( Atomicity )、一致性( Consistency )、隔離性( Isolation )和持續性( Durability )。這四個特性簡稱為 ACID 特性。 
      (1)、原子性 
      事務是資料庫的邏輯工作單位,事務中包含的各操作要麼都做,要麼都不做 
      (2)、一致性 
      事 務執行的結果必須是使資料庫從一個一致性狀態變到另一個一致性狀態。因此當資料庫只包含成功事務提交的結果時,就說資料庫處於一致性狀態。如果資料庫系統 執行中發生故障,有些事務尚未完成就被迫中斷,這些未完成事務對資料庫所做的修改有一部分已寫入物理資料庫,這時資料庫就處於一種不正確的狀態,或者說是 不一致的狀態。 
      (3)、隔離性 
      一個事務的執行不能其它事務干擾。即一個事務內部的操作及使用的資料對其它併發事務是隔離的,併發執行的各個事務之間不能互相干擾。 
      (4) 、持續性 
      也稱永久性,指一個事務一旦提交,它對資料庫中的資料的改變就應該是永久性的。接下來的其它操作或故障不應該對其執行結果有任何影響。 

 

  3 不考慮隔離性產生問題

    (1)髒讀:是指一個事務讀取了另一個事務沒有提交的資料。

      假如A和B各自有100元錢,A向B轉了100元錢,執行update account set money=money+100 while name=‘b’;  update account set money=money-100 while name=‘a’;當第一條執行完,第二條還沒執行,B查詢自己的賬戶,就會發現自己的賬戶多了100元,如果此時A再回滾自己的操作,那麼B之後再查詢自己的賬戶,就會發現自己的錢和之前並沒有變化,還是100

    (2)不可重複讀:在一個事務內讀取表中的某一行資料,多次讀取結果不相同。

      還是上面那個例子,轉賬之前,銀行查詢A的賬戶是100元錢,A向B轉了100之後,銀行 對應上面兩個sql語句並且已經提交,又查詢A賬戶,發現是0元。這就導致了兩次查詢結果不相同。

      注意:不可重複讀有時候是正確的,就像這種情況,正是實際情況需要的,然而有時,不可重複讀是不正確的,比如對某個地區統計GDP,兩次查詢結果不一樣,該怎麼報道呢?所以這種情況又是錯誤的。

      不可重複讀和髒讀的區別,髒讀是讀取前一事務未提交的髒資料,不可重複讀是重新讀取了前一事務已經提交的資料。

    (3)虛讀:是指在一個事務內讀取到了別的事務插入的資料,導致前後讀取不一致。

      假如一個人存款100元沒有提交,這時銀行做報表統計所有使用者的總額為600元,然後這個人提交了這時銀行再統計發現賬戶為700元了,這就是虛讀。

 

  4 設定事務隔離級別

     事務的隔離級別從低到高有:
        Read Uncommitted:最低的隔離級別,什麼都不需要做,一個事務可以讀到另一個事務未提交的結果。所有的併發事務問題都會發生。
        Read Committed:只有在事務提交後,其更新結果才會被其他事務看見。可以解決髒讀問題。
        Repeated Read:在一個事務中,對於同一份資料的讀取結果總是相同的,無論是否有其他事務對這份資料進行操作,以及這個事務是否提交。可以解決髒讀、不可重複讀。
        Serialization:事務序列化執行,隔離級別最高,犧牲了系統的併發性。可以解決併發事務的所有問題。
        通常,在工程實踐中,為了效能的考慮會對隔離性進行折中。

    mysql預設隔離級別 repeatable read

 

Hibernate事務程式碼規範寫法

  程式碼結構

try {
  //開啟事務
  //提交事務
}catch() {
  //回滾事務
}finally {
  //關閉
}
@Test
    void testName() throws Exception {
        
        
        Session session = null;
        Transaction tx = null;
        try {
            
            session= HibernateUtils.openSession();
            tx = session.beginTransaction();
            
            User user = new User();
            user.setUsername("aad陽");
            user.setPassword("pdass");
            user.setAddress("adssd");
            
            //執行到此時會出錯,catch異常,事務回滾
            int i = 10/0;
            
            session.save(user);
            tx.commit();
            
        } catch (Exception e) {
            
            e.printStackTrace();
            tx.rollback();
            
        } finally {
            
            session.close();
            
        }
    }

 

 

Hibernate繫結session

  1 session類似於jdbc的connection,之前web階段學過 ThreadLocal

  2 幫實現與本地執行緒繫結session

  3 獲取與本地執行緒session

    (1)在hibernate核心配置檔案中配置(hibernate.cfg.xml)

        <!-- 與本地執行緒繫結 -->
        <property name="hibernate.current_session_context_class">thread</property>

    (2)呼叫sessionFactory裡面的方法得到

    public static Session getSessionObject() {
        return sessionFactory.getCurrentSession();
    }

  

  4 獲取與本地執行緒繫結session時候,關閉session報錯,不需要手動關閉了