事務的概念和丟失更新的解決方式

一、事務
1.事務的概念:事務是指邏輯上的一組操作,這組操作要麼同時完成要麼同時不完成。參考轉賬操作。
2.如果你自己不去控制事務,數據庫默認一條sql語句就處在自己單獨的事務當中。
3.也可以使用命令去開啓一個事務:
start transaction;--開啓事務,這條語句之後的sql語句將處在一個事務當中,這些sql語句並不會立即執行
Commit--提交事務,一旦提交事務,事務中的所有sql語句纔會執行。
Rollback -- 回滾事務,將之前所有的sql取消。

conn.setAutoCommit(false);
conn.commit();
conn.rollback();
conn.setSavePoint();
conn.rollback(sp);

4.事務的四大特性ACID
~原子性:事務的一組操作是原子的不可再分割的,這組操作要麼同時完成要麼同時不完成。
~一致性: 事務在執行前後數據的完整性保持不變。數據庫在某個狀態下符合所有的完整性約束的狀態叫做數據庫具有完整性。在解散一個部門時應該同時處理員工表中的員工保證這個事務結束後,仍然保證所有的員工能找到對應的部門,滿足外鍵約束。
~隔離性:當多個事務同時操作一個數據庫時,可能存在併發問題,此時應保證各個事務要進行隔離,事務之間不能互相干擾。
~持久性:持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,不能再回滾。

5.事務的隔離性導致的問題(所有的問題都是在某些情況下才會導致問題)
~髒讀:一個事務讀取到了另一個事務未提交的數據。 
1 | a    |  1000
  2 | b    |  1000
 
  b--->a
  start transaction;
  update account set money=money-100 where name='b';
update account set money=money+100 where name='a';
rollback;


select * from account where name = 'a';1000 1000

~不可重複讀:在一個事務內讀取表中的某一行數據,多次讀取結果不同.
start transaction:
活期存款:1000
定期存款:1000
固定資產: 2000
--------------
開啓事務
取走獲取存款1000
提交事務
--------------
總資產:3000

~幻讀(虛讀):一個事務讀取到了另一個事務插入的數據(已提交)
a 2000
b 2000
c 2000
start transaction;
select sum(money) from account;6000
--------------
開啓事務
創建一個賬戶並存入1000塊錢
提交了事務
--------------
select count(*)from account;4
avgMoney = allMoney/count;6000/4=1500

6.數據庫的隔離級別
~Read uncommitted:如果將數據庫設定爲此隔離級別,數據庫將會有髒讀、不可重複度、幻讀的問題。
~Read committed:如果將數據庫設定爲此隔離級別,數據庫可以防止髒讀,但有不可重複度、幻讀的問題。
~Repeatable read: 如果將數據庫設定爲此隔離級別,數據庫可以防止髒讀、不可重複度,但是不能防止幻讀。
~Serializable:將數據庫串行化,可以避免髒讀、不可重複讀、幻讀。

安全性來說:Serializable>Repeatable read>Read committed>Read uncommitted
效率來說:Serializable<Repeatable read<Read committed<Read uncommitted
通常來說,一般的應用都會選擇Repeatable read或Read committed作爲數據庫隔離級別來使用。
mysql默認的數據庫隔離級別爲:REPEATABLE-READ

如何查詢當前數據庫的隔離級別?select @@tx_isolation;
如何設置當前數據庫的隔離級別?set [global/session] transaction isolation level ...;
~此種方式設置的隔離級別只對當前連接起作用。
set transaction isolation level read uncommitted;
set session transaction isolation level read uncommitted;
~此種方式設置的隔離級別是設置數據庫默認的隔離級別
set global transaction isolation level read uncommitted;



8.鎖機制:
共享鎖:共享鎖和共享鎖可以共存。
排他鎖:排他鎖和所有鎖都不能共存。
在非串行化下,所有的查詢都不加鎖,所有的修改操作都會加排他鎖。
在串行化下,所有的查詢都加共享鎖,所有的修改都加排他鎖。
死鎖

9.更新丟失
如果多個線程操作,基於同一個查詢結構對錶中的記錄進行修改,那麼後修改的記錄將會覆蓋前面修改的記錄,前面的修改就丟失掉了,這就叫做更新丟失。
Serializable可以防止更新丟失問題的發生。其他的三個隔離級別都有可能發生更新丟失問題。
Serializable雖然可以防止更新丟失,但是效率太低,通常數據庫不會用這個隔離級別,所以我們需要其他的機制來防止更新丟失:

樂觀鎖和悲觀鎖不是數據庫中真正存在的鎖,只是人們在解決更新丟失時的不同的解決方案,體現的是人們看待事務的態度。
悲觀鎖:認爲每一條sql語句都會出現更新丟失的情況
隔離級別不設置爲Serializable,防止效率過低。
在查詢時手動加上排他鎖。
如果數據庫中的數據查詢比較多而更新比較少的話,悲觀鎖將會導致效率低下。

樂觀鎖:認爲每一條sql語句都不會出現更新丟失的情況
在表中增加一個version字段,在更新數據庫記錄是將version加一,從而在修改數據時通過檢查版本號是否改變判斷出當前更新基於的查詢是否已經是過時的版本。
如果數據庫中數據的修改比較多,更新失敗的次數會比較多,程序需要多次重複執行更新操作。
發佈了24 篇原創文章 · 獲贊 75 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章