关于MySQL变量innodb_rollback_on_timeout一些讨论

本文探讨了 MySQL InnoDB 存储引擎中的 innodb_rollback_on_timeout 参数如何影响事务回滚行为。当设置为 OFF 时,事务仅回滚到最后一个保存点;设置为 ON 时,整个事务将被回滚。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接: http://blog.youkuaiyun.com/lidan3959/article/details/8642706

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,回滚事务。

来自:http://www.cnblogs.com/hustcat/archive/2012/11/18/2775487.html

### 解决MySQL更新时出现锁等待超时的问题 当遇到 `Lock wait timeout exceeded` 错误时,通常是因为事务在尝试获取资源锁定时超过了默认的等待时间。以下是几种可能的原因以及解决方案: #### 原因分析 1. **长时间运行的事务** 如果某些事务执行时间过长,则可能导致其他事务无法获得所需的锁,从而引发超时错误[^1]。 2. **死锁情况** 当两个或多个事务相互持有对方需要的资源并请求被持有的资源时,就会发生死锁现象。数据库检测到这种情况后会终止其中一个事务以解除阻塞状态[^2]。 3. **高并发环境下的竞争** 高并发场景下频繁读写相同的数据行也会增加锁冲突的概率[^3]。 #### 解决策略 ##### 调整参数设置 可以通过修改配置文件中的 `innodb_lock_wait_timeout` 参数来延长或者缩短最大允许的锁等待时间,默认值通常是50秒: ```sql SET GLOBAL innodb_lock_wait_timeout = 120; ``` 此命令将全局范围内的锁等待超时调整为两分钟。对于特定连接也可以单独设定该变量而不影响整个服务器的行为模式。 ##### 查询慢查询日志找出瓶颈所在 启用慢查询记录功能可以帮助识别哪些语句消耗了大量的处理周期甚至引起堵塞状况: ```bash slow_query_log=ON long_query_time=2 log_output='TABLE' ``` 之后可以利用工具如pt-query-digest解析这些数据以便进一步优化性能表现较差的部分。 ##### 使用更细粒度索引来减少全表扫描带来的开销 确保所有的WHERE条件字段都已建立合适的索引结构能够极大地降低访问成本,并间接缓解由争用引起的延迟问题。 ##### 定期维护清理未提交完成的老化事物 定期监控是否有长期挂起而未能正常结束的事物存在非常重要;如果发现此类情形应及时介入解决以免造成连锁反应损害整体效率. ##### 修改应用程序逻辑设计 重新审视业务流程看是否存在不必要的复杂嵌套操作或是可拆分的小型独立单元工作流,这样不仅可以提高吞吐量还能有效规避潜在风险点。 ```python def optimize_transaction(): """ Example function demonstrating how to structure transactions efficiently. Ensure each transaction is as short-lived and focused as possible. """ with db_connection() as conn: cursor = conn.cursor() try: # Begin Transaction cursor.execute("START TRANSACTION;") # Perform necessary updates within minimal scope cursor.execute(""" UPDATE inventory SET stock_level = %s WHERE product_id = %s AND warehouse_id = %s; """, (new_stock_level, product_id, warehouse_id)) # Commit changes immediately after critical section completes conn.commit() except Exception as e: conn.rollback() raise RuntimeError(f"Transaction failed due to {e}") ``` 通过上述方法综合考虑硬件资源配置、软件架构规划等方面因素共同作用才能从根本上解决问题并提升用户体验满意度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值