對mysql事務提交、回滾的錯誤理解

1、原由mysql

  begin或者START TRANSACTION開始一個事務sql

  rollback事務回滾
  commit 事務確認
數據庫

 人們對事務的解釋以下:事務由做爲一個單獨單元的一個或多個SQL語句組成,若是其中一個語句不能完成,整個單元就會回滾(撤銷),全部影響到的數據將返回到事務開始之前的狀態。於是,只有事務中的全部語句都成功地執行才能說這個事務被成功地執行。函數

  這句話自己沒有什麼問題,問題是我給理解錯了,我測試中問題描述爲以下:測試

 mysql事務中有兩條insert語句,其中第二條語句是錯誤的,在運行完事務後,第一條仍然插進去了,代碼以下。spa

 //建立表:
CREATE TABLE `test_tab` (
`f1`  int(11) NOT NULL ,
`f2`  varchar(11)  DEFAULT NULL ,
PRIMARY KEY (`f1`)
)
ENGINE=InnoDB

//執行事務:
START TRANSACTION;
INSERT INTO test_tab VALUES    (1, '2');
INSERT INTO test_tab VALUES    (1, '3');
COMMIT;

(錯誤:這只是我一開始的認爲)一開始認爲只要把事務寫出來,最後用commit提交一下,數據庫會自動判斷這些語句是否全執行成功,若是成功則把全部的數據插入到數據庫,若是有一條失敗就自動回滾至原始狀態!顯然我認爲錯了。3d

我執行上面的語句後的結果是:code

[SQL]START TRANSACTION;blog

受影響的行: 0事務

時間: 0.000s

[SQL]

INSERT INTO test_tab VALUES (1, '2');

受影響的行: 1

時間: 0.001s

[SQL]

INSERT INTO test_tab VALUES (1, '3');

[Err] 1062 - Duplicate entry '1' for key 'PRIMARY'

咱們看結果能夠知道INSERT INTO test_tab VALUES (1, '3');這一句由於主鍵衝突運行失敗,從而這一條下面的commit也沒有執行。

須要注意的是:這時已經開啓了一個事務,而且已經執行了一條正確的插入語句,雖然沒有體如今數據庫中,但若是之後在該鏈接中又執行了一條commit beginstart transaction新開一個事務會將該連接中的其餘未提交的事務提交,至關於commit)你會發現已經將剛纔的INSERT INTO test_tab VALUES (1, '2');寫進了數據庫。

 

因此事務的回滾不是這麼理解的,正確的理解應該是,若是事務中全部sql語句執行正確則須要本身手動提交commit;不然有任何一條執行錯誤,須要本身提交一條rollback,這時會回滾全部操做,而不是commit會給你自動判斷和回滾。

 

二 解決辦法

  1. C++調用方式:(簡單示例)

先定義一個變量標誌bool m_flag=true;

再執行事務和sql語句如:(execute爲本身寫的函數,以下)

execute( m_sqlCon, 「begin」);

execute(m_sqlCon,」INSERT INTO test_tab VALUES (1, '2')」);

execute(m_sqlCon,」INSERT INTO test_tab VALUES (1, '3')」);

若是執行過程當中任意一語句出錯則將該標誌m_flag置爲false

這時不該該去提交commit,而是用一個函數去判斷標誌是否爲false,若是爲false說明執行的sql語句中有失敗的,就執行rollback,不然說明所有正確,執行commit。以下面的 commit_transaction()方法。

 

代碼大體以下,如使用須要修改!

 1 privat void execute(MYSQL m_sqlCon, string sqlStatement)
 2 {
 3 r = mysql_real_query(m_sqlCon, sqlStatement, (unsigned long)strlen(sqlStatement));
 4     if (r)
 5         m_flag = false; // 出錯則標記一下
 6 }
 7 public bool commit_transaction()
 8 {
 9         int ret_error = 0;
10         if (!m_flag)
11         {
12             cancel_transaction();
13             return false;
14         }
15         else
16         {
17             if (!(ret_error = mysql_commit(m_sqlCon)))
18             {
19                 cancel_transaction();
20                 return true;
21             }
22         }
23         return true;
24 }

 

2.利用存儲過程:

 1 CREATE PROCEDURE PRO2()
 2 BEGIN
 3     DECLARE t_error INTEGER;
 4     DECLARE    CONTINUE HANDLER FOR SQLEXCEPTION SET t_error = 1;
 5 
 6     START TRANSACTION;
 7         INSERT INTO test_tab VALUES    (1, '2');
 8         INSERT INTO test_tab VALUES    (1, '3');
 9         
10         IF t_error = 1 THEN
11             ROLLBACK;
12         ELSE
13             COMMIT;
14         END IF;
15 END

 

而後調用 CALL  PRO2()

這個直接能夠利用mysql去決定他應該是回滾仍是提交。

相關文章
相關標籤/搜索