JAVA中事務的並發機制


第一節:事務的並發處理ACID

Atomicity   原子性

Consistency 一致性

Isolation  隔離性

Durability 持久性

第二節:事務並發可能出現的問題

2.1第一類丟失更新(Lost Update)

說明:事務B的更新丟失。撤銷一個事務影響到另外一個事務

時間

取款事務A

存款事務B

T1

開始事務

 

T2

 

開始事務

T3

查詢賬戶余額1000元

 

T4

 

查詢賬戶余額1000元

T5

 

匯入100元把余額改成1100元

T5

 

提交事務

T7

取出100把余額變成900

 

T8

撤銷事務

 

T9

余額恢復1000(丟失更新)

 

 

2.2臟讀(ditrty read)

說明:讀到了別的事務還提交的事務,此時B事務還未提交,中間的事務可能回滾,所以讀到數據可能不對。

時間

取款事務A

存款事務B

T1

開始事務

 

T2

 

開始事務

T3

 

 

T4

 

查詢賬戶余額1000元

T5

 

匯入100元把余額改成1100元

T5

查詢賬戶余額1100元

(讀取的臟數據)

 

T7

 

回滾

T8

取款1100元

 

T9

提交事務失敗

 

 

2.3不可重復讀(non-repeatable read)

當前事務已經讀取的數據記錄,被其他事務修改或刪除

說明:同一個事務中讀取兩遍的值不一致,此時無法確定按哪個值來處理。

時間

取款事務A

存款事務B

T1

開始事務

 

T2

查詢賬戶余額1000元

 

T3

 

開始事務

T4

 

匯入100元賬戶余額改為1100元

T5

 

提交事務

T5

查詢賬戶余額1100元

 

T7

 

 

T8

提交事務

 

 

 

2.4第二類丟失更新(second lost update)

說明:不可重復讀的特殊情況,本來A事務在提交之前應該再次讀一遍數據,讀取的數據還是和第一次是不一致的。

時間

取款事務A

存款事務B

T1

 

開始事務

T2

開始事務

 

T3

 

查詢賬戶余額1000元

T4

查詢賬戶余額1000元

 

T5

 

取款100元把余額改成900元

T5

 

提交事務

T7

匯入100元

 

T8

提交事務

 

T9

余額改成1100元

 

 

 

2.5幻讀(phantom read)

說明:此時兩次機查詢的數據不一致,同不可重復讀,兩次查詢出來的數據不一致。幻讀為插入和刪除的操作,以上為更新的操作。

其他事務插入了新的數據,當前事務以相同的查詢條件,在那個事務插入數據之前和之后查詢數據,得到的數據記錄的條數不一樣。

時間

查詢學生事務A

查詢學生事務B

T1

開始事務

 

T2

 

開始事務

T3

查詢學生為10人

 

T4

 

插入1個學校

T5

查詢學生為11人

 

T5

 

提交事務

T7

提交事務

 

 

 

第三節:JDBC事務隔離級別

(1):TRNSACTION_NONE:不支持事務

(2):TRNSACTION_READ_COMMITTED:防止臟讀和幻讀,但是不能限制不可重復讀,因為不可重復讀是讀取已經提交的事務,幻讀類似

(3):TRNSACTION_READ_UNCOMMITTED:允許臟讀,幻讀,不可重復讀

(4):TRNSACTION_REPEATABLE_READ(可重復讀):MYSQL默認設置級別,即把這條數據讀取出來以后加把鎖,其他事務不能更新這條數據的值,等我這個事務處理完成后其他事務才能對該條數據做更新,select xxx rom xxxtable where xxx for update,數據庫為其讀取的這條記錄加把鎖,這條事務沒提交之前,其他事務就不能更新這條記錄

(5):TRNSACTION_SERIALIZABLE:無論多少事務來都不並發,一個一個執行

 

第四節:悲觀鎖和樂觀鎖

4.1悲觀鎖和樂觀鎖說明

利用悲觀鎖和樂觀鎖解決不可重復讀(non-repeatable read)問題設成READ_COMMITTED通過hibernate實現。

悲觀鎖:通過數據庫加鎖(for update)

樂觀鎖:1:事務取出數據庫中一條記錄的時候為其設置一個version號

2:如果有事務更新了這條數據version版本號自動加一

3:事務把數據更改后檢查版本號是否是剛取出來的那個version,如果不一樣事務    回滾,否則會沖掉人家修改后的數據。

4.2 Hiernate悲觀鎖和樂觀鎖實例

Session session1 = sf.openSession();

Session session2 = sf.openSession();

session1.beginTransaction();

Account a1 = (Account )session1.load(Account .class,1); //把數據庫記錄load出來

 

session2.beginTransaction();

Account a2 = (Account )session2.load(Account .class,1);

a1.setBalance(100);

a2.setBalance(300);

 

session1.getTransaction.commit();

session2.getTransaction.commit();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM