不要在儲存過程中控制事務

壹頁書發表於2016-06-01
MySQL技術內幕 InnoDB儲存引擎 344頁.

原來看過這段,總而言之,就是MySQL不要在儲存過程中控制事務.
當時沒有仔細看細節,只是記住了一個結論.
畢竟都21世紀了.還有用儲存過程的?
但是..#(×&%¥×&@……&……#@&

以如下過程為例.
  1. drop table nums;  
  2. drop procedure pCreateNums;  
  3.   
  4. create table nums(id int not null primary key);  
  5.   
  6. delimiter $$  
  7. create procedure pCreateNums(cnt int)  
  8. begin  
  9.     -- declare exit handler for sqlexception rollback;  
  10.     start transaction;  
  11.     insert into nums(id) values(cnt+rand()*100);      
  12.     insert into nums(id) values(cnt);  
  13.     commit;  
  14. end $$  
  15. delimiter ;  
  16.   
  17. call pCreateNums(10);  
  18. call pCreateNums(10);  

連續呼叫兩次過程,會觸發主鍵衝突的異常.
最後的commit沒有執行,第二個過程的事務並未完成.


這時,需要上層呼叫的程式,進行事務的提交或者回滾.

當然,也可以定義一個Handler進行異常處理.
  1. drop table nums;  
  2. drop procedure pCreateNums;  
  3.   
  4. create table nums(id int not null primary key);  
  5.   
  6. delimiter $$  
  7. create procedure pCreateNums(cnt int)  
  8. begin  
  9.     declare exit handler for sqlexception rollback;  
  10.     start transaction;  
  11.     insert into nums(id) values(cnt+rand()*100);      
  12.     insert into nums(id) values(cnt);  
  13.     commit;  
  14. end $$  
  15. delimiter ;  
  16.   
  17. call pCreateNums(10);  
  18. call pCreateNums(10); 



第一個過程執行成功,第二個過程觸發異常處理自動回滾
但是,上層的JAVA程式對於這一切,都透明瞭..
他後續的工作怎麼處理?
快取是否更新?分散式架構下,任務還繼續嗎?給客戶端返回什麼?

所以,過程和JAVA程式還得約定異常的型別.
  1. drop table nums;  
  2. drop procedure pCreateNums;  
  3.   
  4. create table nums(id int not null primary key);  
  5.   
  6. delimiter $$  
  7. create procedure pCreateNums(cnt int)  
  8. begin  
  9.     declare exit handler for sqlexception begin rollback;select -1;end;  
  10.     start transaction;  
  11.     insert into nums(id) values(cnt+rand()*100);      
  12.     insert into nums(id) values(cnt);  
  13.     commit;  
  14.     select 1;  
  15. end $$  
  16. delimiter ;  



這樣約定異常的常量,把異常處理,自己又實現了一遍.

MSSQL 可以自動回滾事務,並且會丟擲異常,上層JAVA開發可以捕獲這個異常.
但是MySQL還是做不到的.

所以事務控制最好由程式端完成.

  1. drop table nums;  
  2. drop procedure pCreateNums;  
  3.   
  4. create table nums(id int not null primary key);  
  5.   
  6. delimiter $$  
  7. create procedure pCreateNums(cnt int)  
  8. begin  
  9.     start transaction;  
  10.     insert into nums(id) values(cnt+rand()*100);      
  11.     insert into nums(id) values(cnt);  
  12. end $$  
  13. delimiter ; 

JAVA程式呼叫過程之前,開啟事務,然後呼叫過程,根據過程的執行情況,提交或者回滾.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-2112572/,如需轉載,請註明出處,否則將追究法律責任。

相關文章