博客 / 詳情

返回

MySQL存儲過程回滾

MySQL存儲過程出錯回滾是保證數據一致性的重要措施,如何處理好存儲過程出錯後的回滾,請看回滾處理步驟及需要注意的幾個事項:
MySQL存儲過程回滾
首先看一下當前MySQL數據庫是否已經開啓了自動提交。
在數據庫中,使用Mysql>show variables like ‘autocommit’;
Vaiable_name Value
Autocommit On
在存儲過程中,有兩種方式進行回滾和提交操作,第一種方式採用開啓事務的方法;第二種採用關閉自動提交的方法,值得時在存儲過程中關閉,而不是整個數據庫關閉。
以下操作是在數據庫是自動提交的情況中演示的:
一、第一種方法開啓事務。
準備兩個存儲過程分別是NewTest和NewTest1,一張數據表test111:
Id
1
2
3
4
單個存儲過程
1.回滾:單純的一個存儲過程NewTest,如果想要進行回滾或者提交操作的時候需要開啓事務,否則每執行一個更新或者刪除操作都會被自動提交。
CREATE DEFINER=root@% PROCEDURE NewTest()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=1; #刪除操作
Rollback; #回滾
commit; #提交
END;
結果:(刪除操作回滾後,數據不變)
Id
1
2
3
4
2.提交
CREATE DEFINER=root@% PROCEDURE NewTest()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=1; #刪除操作
commit; #提交
END
結果:(id=1的刪除掉了)
兩個存儲過程NewTest為父,NewTest1為子,父調子:
CREATE DEFINER=root@% PROCEDURE NewTest()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=1; #刪除操作
Call NewTest1();
delete from test111 where id=3; #刪除操作
commit; #提交
End;

CREATE DEFINER=root@% PROCEDURE NewTest1()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=2; #刪除操作
commit; #提交
END
結果:只剩下id=4
3.父子都開啓事務,夫回滾,子提交:
CREATE DEFINER=root@% PROCEDURE NewTest()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=1; #刪除操作
Call NewTest1();
delete from test111 where id=3; #刪除操作
Rollback; #回滾
commit; #提交
End;

CREATE DEFINER=root@% PROCEDURE NewTest1()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=2; #刪除操作
commit; #提交
END

結果:只剩下ID=4的記錄

4.父子都開啓事務,夫回滾,子回滾:
CREATE DEFINER=root@% PROCEDURE NewTest()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=1; #刪除操作
Call NewTest1();
delete from test111 where id=3; #刪除操作
Rollback; #回滾
commit; #提交
End;

CREATE DEFINER=root@% PROCEDURE NewTest1()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=2; #刪除操作
Rollback; #回滾
commit; #提交
END

結果:剩下ID=2,4的記錄
5.父子都開啓事務,夫提交,子回滾:
CREATE DEFINER=root@% PROCEDURE NewTest()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=1; #刪除操作
Call NewTest1();
delete from test111 where id=3; #刪除操作
commit; #提交
End;

CREATE DEFINER=root@% PROCEDURE NewTest1()
BEGIN
START TRANSACTION; #開啓事務
delete from test111 where id=2; #刪除操作
Rollback;
commit; #提交
END
結果:剩下ID=2,4的記錄
從以上四個例子可以得出結論:在十五開啓中,有且只能有一個事務能夠被開啓,當子存儲過程開啓了事務後,前面父事務自動失效,相當於沒有開啓過事務(也可以認為是第二個事務會將第一個事務給提交掉)。只要開啓了事務之後,後面的代碼都將被十五所管轄。所以推薦,只讓父親開啓事務,這樣能夠醬紫存儲過程也包含到父存儲過程的事務中,實現多個存儲過程回滾和提交的一致性。
如果子存儲過程既可以當父親,也可以檔子存儲過程,那麼推薦用一個輸入參數來判定,當前他是做為父親還是兒子,做為父親就開啓事務並負責自己的提交和回滾;做為兒子就不開啓事務,接受父親的管轄,提交和回滾操作也都交於父親來執行。重要的一點必須在李凱存儲過程之前需要有個提交或者是回滾的操作做為結束。
二、第二種方法關閉自動提交事務設置
在test111中增加id=12,13,14,15三條記錄
存儲過程如下:
CREATE DEFINER=root@% PROCEDURE NewTest()
BEGIN
Set autocommit=0; # 關閉自動提交
Update test111 set id=66 where id=12; #修改操作
Commit;#提交
Update test111 set id=77 where id=13; #修改操作
Rollback;#回滾
Update test111 set id=88 where id=14; #修改操作
Commit; #回滾
commit; #提交
End;
執行後的結果:
Id
13
15
66
88
關閉自動調教的方法比開啓事務更加簡潔,當存儲過程關閉自動提交後,遇到commit將會提交,遇到rollback將會回滾。Commit和rollback互不干擾,不具備包含關係,就如上圖所示,commit之後到rollback之前的代碼,採後rollback管轄。
已開啓事務的方法一樣,父存儲過程可以掌控子存儲過程(被調用的子存儲過程就相當於一段下載父存儲過程的代碼,與其他父中的代碼地位相等)。而且set autocommit=0作用範圍不侷限於begin-end之間,只要是set autocommit=0之後的代碼,都會被其所管轄,最重要一點,一旦set autocommit=0,必須在李凱存儲過程之前需要有個commit或rollback的操作做為結束,否則沒被提交或回滾的那段代碼中操作過增刪改的表將會被鎖住。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.