MySQL 事務管理


 

事務的4個特性(ACID)

  • 原子性 Atomicity。每個事務中的操作,要么都成功,要么都失敗
  • 一致性 Consistency。事務執行前后,數據庫中的數據應該保持一致
  • 隔離性 Isolation。事務之間應該是隔離的,事務之間互不影響、干擾
  • 持久性 Durability。事務一旦提交,便會將修改持久化到數據庫

 

 

事務管理的相關命令

start transaction;  #開始事務
sql語句1;
sql語句2;
.....

commit; #提交事務

#rollback; #回滾

 

 

 

流程示例

start transaction;

insert into tb_user (name,age) values ('zhangsan',20);  #顯示Query OK,這條sql語句可以成功執行

insert into tb_user (name,age) values ('李四','age');  #顯示ERROR,發生錯誤。只是說這條語句執行錯誤,但后面還可以執行sql語句

insert into tb_user (name,age) values ('wangwu',20);  #顯示Query OK,

 

如果此時commit;提交,會把執行成功的2個sql語句做的修改持久化數據庫,失敗的sql語句則忽略。

其實發生ERROR時,為了做到事務的原子性,就應該rollback;回滾。

並不是說start transaction;  .....  commit;  會自動維持事務的4個特性,全部成功就持久化到數據庫,某些sql語句發生錯誤,就自動回滾,不是這樣的。

事務的4個特性需要我們自己來維持。

 

 

代碼中使用事務也一樣:

......   //開啟事務

try{

  ..... //要執行的多條sql語句

      commit;  //若前面都正常執行,則提交

}catch(Exception e){

  rollback;  //發生錯誤就回滾

}

先開啟事務,把要執行的多個sql語句放到try中,都正確執行那就提交,發生錯誤就回滾。

 

 


 

 

catch就是對異常的處理,既然捕獲了異常進行了處理,就不會往上一級拋了。

如果每一級都是throws往上拋,拋到JVM,JVM默認的異常處理方式是:打印異常信息,終止程序運行。

 

比如說下面這段代碼:

        System.out.println(1);
        try{
            System.out.println(1/0);
        }catch (Exception e){
            System.out.println("error");
        }
        System.out.println(2);
1
error
2

並不會自動在控制台打印異常信息,終止程序。

要看異常信息,可以在catch中 System.out.println(e.getMessage()); 打印出來

 

 


 

 

 

事務的並發

事務的並發即同時執行多個事務,主要涉及事務的隔離性、隔離級別。

 

1、事務並發執行可能出現的問題

(1)臟讀     一個事務讀取其它事務尚未提交的數據

事務B對數據庫做了修改(執行成功但尚未提交),事務A讀取這些已修改的記錄,A讀取之后,B進行了回滾,A讀取到的數據變成了臟數據、無效數據,即臟讀。

隔離級別 Read commited 已提交讀,可解決臟讀問題,等到使用這些記錄的事務提交后才讀取數據。

 

 

(2)不可重復讀     前后多次讀取,讀取的數據內容不一致(期間進行了update操作)

比如說我卡里有2000,打算在ATM上取款2000,輸入取款金額2000點擊確定,系統查詢賬戶余額,還有2000,是夠的;

我老婆的微信綁定了我的卡,這時把我卡里的1000給花了,賬戶余額為1000

ATM執行扣款-2000(在賬戶余額的基礎上扣,money-2000,又要獲取賬戶余額),並往外吐錢2000,1000-2000=-1000

ATM前后2次讀取余額(同一條記錄的數據),讀取的數據內容不一致,這就出現問題了。

 

隔離級別 Repeatable read 重復讀,可解決不可重復讀的問題,當有事務讀了某些行的數據后,這些行會被鎖住,不允許其它事務對這些行進行修改,這樣重復讀取到的數據就是一致的。

因為使用某些行時,這些行會被鎖定,其它事務不能讀取這些(可能會被修改的)行,也避免了臟讀問題。

 

 

(3)幻讀(虛讀)   前后多次讀取,讀取的記錄數不一致(期間進行了insert、delete操作)

隔離級別 Serializable 可解決幻讀問題,不允許事務並發,最安全,但性能最差,基本不用。

 

以上3個是讀問題,還可能產生一個寫問題:丟失更新。

 

(4)丟失更新  丟失更新是不可重復讀中的一種特殊情況,2個事務都要修改記錄內容(update),后提交的覆蓋了前面提交的

 

時間 取款事務 支票轉賬事務
T1 開始事務  
T2   開始事務
T3 查詢賬戶余額為1000元  
T4   查詢賬戶余額為1000元
T5 取出100,把存款余額改為900元  
T6 提交事務  
T7   匯入100元,把存款余額改為1100元
T8   提交事務

-100的更新操作丟失了。

 

 

 

2、4種隔離級別

  • Read uncommitted:未提交讀,解決不了任何讀問題,安全性最低,但事務執行效率最高
  • Read committed:已提交讀,解決了臟讀,但不可重復讀、虛讀有可能發生。oracle默認值。
  • Repeatable read:重復度,解決了臟讀、不可重復讀,但虛讀有可能發生。mysql默認值。
  • Serializable:串行化,不允許事務並發,可解決所有並發問題,安全性最高,但事務執行效率最低

一般折中選擇第2、3項,使用默認的即可,不必進行設置。

 

 

 

3、查看、設置隔離級別


#mysql
5
select @@tx_isolation; #查看當前會話使用的隔離級別
select @@global.tx_isolation; #查看全局設置的隔離級別


#mysql 8
select @@transaction_isolation;
#查看當前會話使用的隔離級別
select @@global.transaction_isolation; #查看全局設置的隔離級別
#mysql5、mysql8的查看方式不同,5是tx,8是transaction,如果不對應會報錯Unknown system variable 'tx_isolation'|'transaction_isolation'


#設置事務的隔離級別,5、8一樣
set session transaction isolation level repeatable read; #設置當期會話使用的隔離級別為repeatable read
set global transaction isolation level repeatable read; #設置全局使用的隔離級別是repeatable read

 

 


 

 

如果我們沒有使用start transaction開啟事務,默認把一條sql語句(帶分號)作為一個事務處理,會自動提交。

 


免責聲明!

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



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