MySQL 5.6 5.7 如何自定义行锁超时等待(wait timeout)时间 innodb_lock_wait_timeout

1. 问题

最近由于业务的需要,写了个基于数据库锁机制的分布式调度简易框架,用于处理业务中的补偿任务和定时轮询任务。由于调度任务处理时间长短不一,有些是几秒处理完,而有些需要好几分钟。对于处理时间较长的任务,在事务中,行锁会一直占据直到事务处理结束。

那么问题就来了,对于时间处理较长的任务,再下一轮调度起来之前事务还没处理完,这个时候,下个事务会在行锁上一直等待下去,直到timeout。这样会占据多个线程、消耗多数数据库资源。

2. 解决思路、方案

思路也很简单,当检测到数据库行锁被占据时,当前线程立马结束,不进行锁释放等待,这样既节约线程资源也节省数据库资源。

我们知道,MySQL8是支持 'SELECT ... for update NOWAIT' 这种写法的,但是对于5.x版本这种写法并不支持(图 - 1),恰巧我们用的是5.6版本,我们需要另外想办法来解决。

图 - 1

思路1: 在MYSQL系统变量里面(global variable, session variable)中有特定的变量用来控制这个行锁超时等待时间,我们可以修改这变量值,来使得我们的等待超时时间缩短

思路2: 比较好的方案,我们只修改当前会话的,而不修改全局变量值(有可能多个程序在连你的数据库)

思路3: 到底哪个变量控制这行锁的超时等待时间呢?通过网上查询,我们可以知道有一个叫 'innodb_lock_wait_timeout' 的变量正是我们要寻找的东东。 MySQL对于超时相关的变量有很多,大家可以查询information_scheme.global/session_variables表 (5.7版本略微不同,需要在performance_schema去查询):

select * from information_schema.global_variables where variable_name like '%timeout%';

你会看到有很多相关的变量,每个变量的含义,大家可以网上查找一下,了解一下很有必要!!这里我们只关心 「innodb_lock_wait_timeout」这个变量,默认值是 50秒,表示: 行锁等待超时时间是50秒。

图 - 2

好了,问题根源我们也找到,现在的问题是怎么做?!

思路1:数据库的操作流程其实也挺直接明了的:

定义DataSource -> 从DS池中获取Connection -> 通过connection执行SQL

涉及到事务的,其实也就是在第二步获取connection后在执行第三部前,执行事务相关操作(在动态代理中),比如:执行 begin语句(start transaction语句效果也一样)

思路2:我们能否在Connection创建的时候,就把 innodb_lock_wait_timeout的值给修改了呢?答案是可以的。

Springboot中默认的数据库连接池用的是 Hikari,而它刚好有可配置属性:connectionInitSql,通过代码跟踪,可以知道这个SQL在创建connection的时候会被执行。这个正好是我们想要的!!!!好了,其他不多说了,上代码吧!!

通过 SET语句,我们可以设置SESSION级别的值(图 - 3)

图 - 3

3. 测试用例

图 - 4

4. 总结

这个问题,项目中存在有一段时间了,一直都没有时间沉下心来研究,这周趁着项目空闲期终于搞出了这个方案,下周上线,线上观察一段时间。

5. 附图

有同学问及到有关方法的代码,现黏贴一下:

lockAgain()方法

附图1

lockRowFor1000Seconds()方法

附图2
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、概述 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种...
    不变甄心阅读 2,751评论 0 3
  • https://blog.csdn.net/steven_liwen/article/details/531884...
    SkTj阅读 2,394评论 0 16
  • 今天看到一位朋友写的mysql笔记总结,觉得写的很详细很用心,这里转载一下,供大家参考下,也希望大家能关注他原文地...
    信仰与初衷阅读 4,765评论 0 30
  • 文章导读: 累兮,累兮,要死兮...... 本文解决问题: 1、表级锁定(读锁、写锁) 2、行级锁定(共享锁、排他...
    创造new_world阅读 657评论 0 1
  • 最近碰到几个业务场景,会遇到并发的问题。在单实例情况下,我们会通过java.util.concurrent包...
    菜鸟小玄阅读 2,277评论 0 5