zoukankan      html  css  js  c++  java
  • MySQL InnoDB加锁超时回滚机制(转)

    add by zhj: 看来我对MySQL的理解还有待深入,水还是挺深的啊,MySQL给记录加锁时,可以通过innodb_lock_wait_timeout参数设置超时时间,

    如果加锁等待超过这个时间,就会回滚,但回滚的话有两种方式:第一种:回滚当前加锁的这条语句;第二种:回滚整个事务。这两种方式是通过参数

    innodb_rollback_on_timeout来控制的。如果是OFF,表示加锁超时回滚时,只回滚加锁超时的那条SQL语句;如果是ON,表示回滚整个事务。默认

    是OFF。在《MySQL Admin Cookbook》一书中,作者强烈建议该参数设置为ON,但其实OFF也没关系,你可以在应用程序中捕获那个加锁超时,然

    后应用程序去执行ROLLBACK,这样就可以保证原子性,只要你没执行COMMIT,就不会破坏原子性。Django应该就是这么做的。我个人拙见是:感觉

    设置为ON,依靠数据库本身自动完成回滚更好一些。

    原文:http://www.cnblogs.com/hustcat/archive/2012/11/18/2775487.html

    1innodb_rollback_on_timeout变量

    下面是MySQL官方手册关开innodb_rollback_on_timeout变量的说明:

    In MySQL 5.0.13 and 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,回滚事务。

  • 相关阅读:
    设置Sysctl.conf用以提高Linux的性能(最完整的sysctl.conf优化方案)
    XSS攻击及防御
    通过Nginx,Tomcat访问日志(access log)记录请求耗时
    nginx配置长连接
    nginx常见内部参数,错误总结
    nginx 并发数问题思考:worker_connections,worker_processes与 max clients
    Nginx与Tomcat、Client之间请求的长连接配置不一致问题解决[转]
    JavaScript的基准测试-不服跑个分?
    延迟求值-如何让Lo-Dash再提速x100?
    如果把编程语言当成座驾
  • 原文地址:https://www.cnblogs.com/ajianbeyourself/p/6956417.html
Copyright © 2011-2022 走看看