關於MySQL變量innodb_rollback_on_timeout一些討論


1innodb_rollback_on_timeout變量

下面是MySQL官方手冊關開innodb_rollback_on_timeout變量的說明:

In MySQL 5.0.13 a nd up, InnoDB rolls back only the last statement on a transaction timeout by default. If --innodb_rollback_on_timeout is specified, a transaction timeout causes InnoDB to abort and roll back the entire transaction (the same behavior as before MySQL 5.0.13). This variable was added in MySQL 5.0.32.

該變量默認值為OFF,如果事務因為加鎖超時,會回滾上一條語句執行的操作。如果設置ON,則整個事務都會回滾。

 

下面通過一個示例來驗證上面這段話。

2、示例

(1) innodb_rollback_on_timeoutOFF

Session 1

Session 2

mysql> create table tt(c1 int primary key, c2 int)engine=innodb;

Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt values(1, 1);

Query OK, 1 row affected (0.00 sec)

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from tt where c1=1 lock in share mode;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    1 |

+----+------+

1 row in set (0.00 sec)

 

 

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

 

mysql> insert into tt values(10,10);

Query OK, 1 row affected (0.00 sec)

 

mysql> delete from tt where c1=1;

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> select * from tt;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    1 |

| 10 |   10 |

+----+------+

2 rows in set (0.00 sec)

 

mysql> rollback;

Query OK, 0 rows affected (0.01 sec)

 

mysql> select * from tt;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    1 |

+----+------+

1 row in set (0.00 sec)

mysql> select * from tt;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    1 |

+----+------+

1 row in set (0.00 sec)

 

 

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

 

mysql> insert into tt values(10,10);

Query OK, 1 row affected (0.00 sec)

 

mysql> delete from tt where c1=1;

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> commit;

Query OK, 0 rows affected (0.02 sec)

 

mysql> select * from tt;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    1 |

| 10 |   10 |

+----+------+

2 rows in set (0.00 sec)

session2因為加鎖超時,事務回退到上一條語句。 

 

(2) innodb_rollback_on_timeoutON

Session 1

Session 2

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from tt where c1=1 lock in share mode;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    1 |

+----+------+

1 row in set (0.00 sec)

 

 

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

 

mysql> insert into tt values(11,11);

Query OK, 1 row affected (0.00 sec)

 

mysql> delete from tt where c1=1;

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> select * from tt;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    1 |

| 10 |   10 |

+----+------+

2 rows in set (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from tt;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    1 |

| 10 |   10 |

+----+------+

2 rows in set (0.00 sec)

session2加鎖超時,整個事務回滾。

 

3、總結

innodb_rollback_on_timeoutOFF,事務會回滾到上一個保存點,InnoDB在執行每條SQL語句之前,都會創建一個保存點,參見代碼:

int

row_insert_for_mysql(

                                               /* out: error code or DB_SUCCESS */

         byte*                 mysql_rec,       /* in: row in the MySQL format */

         row_prebuilt_t*     prebuilt)  /* in: prebuilt struct in MySQL

                                               handle */

{

。。。

         savept = trx_savept_take(trx);

。。。

如果事務因為加鎖超時,相當於回滾到上一條語句。但是報錯后,事務還沒有完成,用戶可以選擇是繼續提交,或者回滾之前的操作,由用戶選擇是否進一步提交或者回滾事務。

innodb_rollback_on_timeoutON,整個事務都會回滾。這可以從row_mysql_handle_errors函數中得到驗證。

ibool
row_mysql_handle_errors(
/* ==================== */
                 /*  out: TRUE if it was a lock wait and
                we should continue running the query thread 
*/
    ulint*        new_err, /*  out: possible new error encountered in
                lock wait, or if no new error, the value
                of trx->error_state at the entry of this
                function 
*/
    trx_t*        trx,     /*  in: transaction  */
    que_thr_t*    thr,     /*  in: query thread  */
    trx_savept_t*    savept)     /*  in: savepoint or NULL  */
{
...
else  if (err == DB_DEADLOCK  // 發生死鎖
           || err == DB_LOCK_TABLE_FULL
           || (err == DB_LOCK_WAIT_TIMEOUT
               && row_rollback_on_timeout)) {
         /*  Roll back the whole transaction; this resolution was added
        to version 3.23.43 
*/

        trx_general_rollback_for_mysql(trx, FALSE, NULL);  // 事務全部回滾
                
    }  else  if (err == DB_OUT_OF_FILE_SPACE
           || err == DB_LOCK_WAIT_TIMEOUT) {

        ut_ad(!(err == DB_LOCK_WAIT_TIMEOUT
                && row_rollback_on_timeout));

                if (savept) {  // 回滾到上一個保存點
             /*  Roll back the latest, possibly incomplete
            insertion or update 
*/

            trx_general_rollback_for_mysql(trx, TRUE, savept);
        }
         /*  MySQL will roll back the latest SQL statement  */
...

 

問題:innodb_rollback_on_timeout為OFF,事務的原子性被破壞了嗎?

答:NO,從示例中可以看到,事務只是回退上一條語句的狀態,而整個事務實際上沒有完成(提交或者回滾),而作為應用程序在檢測這個錯誤時,應該選擇是提交或者回滾事務。如果嚴格要求事務的原子性,當然是執行ROLLBACK,回滾事務。

 


作者:MrDB
出處:http://www.cnblogs.com/hustcat/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

 

 


免責聲明!

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



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