开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题,有需求都可以加群群内,可以解决你的问题。加群请联系微信 liuaustin3 ,(共1910人左右 1 + 2 + 3 + 4 +5) 4群(410+ 默认加5群),另欢迎 OpenGauss 的技术人员加入。
最近有一个需求关于数据的清理的需求,但是这个需求里面有一个部分有一个部分是特殊,也就是在数据清理中,是需要进行数据的导出和导入的,并确定在导入和导出的过程中,导出数据在导出到清理的整个过程中中不能被改变,不能进行commited这些数据需要具有独占性 。
这里要完成这个事情,可以采用对于要迁移的行进行锁定的方法来进行,但锁定的方法可以用 select * from table where 条件 for update; 但问题的重点是, 在不同的MYSQL配置中会产生什么样的结果,不同的结果开发是否能接受的问题。
这里有一个相关的说明和测试的大纲
1 MYSQL innodb_lock_wait_timeout = 更长的时间如 86400 和 innodb_deadlock_detect =ON
2 MYSQL innodb_lock_wait_timeout =3 和 innodb_deadlock_detect = OFF 的情况
在不同场合下,MySQL 在这两边有不同的设置可能性,在一些早期的MYSQL 和互联网的情况下,innodb_deadlock_detect 是为OFF的,并且在 innodb_lock_wait_timeout = 3 也就是不管怎么样,只要出现互斥的状态下,锁超时为3秒,当然这里也包含了死锁的情况,死锁不超过3秒,这里是通过系统锁超时来进行判断的,当然blocked 的情况也是3秒内解决。
但在一些传统性的单位,也有另外的一种配置,innodb_deadlock_detect =ON 并且因为程序编制和需求的原因blocked 的时间都设置的较长并不和互联网设置的相同。
这里需要在不同的情况下来分析,同样的设置给应用程序带来的不同的问题。
这里先从互联网的方案来说,死锁探测为0 innodb_lock_wait_timeout = 3 当然有的地方更短设置成1秒。具体什么成因这里就不讨论了,同时这里还有一个不同就是隔离级别,我们在每次测试使用不同的隔离级别来看看会有什么影响。
编号 | 数据库参数 | session 隔离 | 操作类型 |
1 | 不探测死锁 3秒解锁 | read commit | 更新 |
2 | 不探测死锁 3秒解锁 | repeatable read | 更新 |
3 | 不探测死锁 3秒解锁 | read commit | 删除 |
4 | 不探测死锁 3秒解锁 | repeatable read | 删除 |
5 | 探测死锁,不解锁 | read commit | 更新 |
6 | 探测死锁,不解锁 | repeatable read | 更新 |
7 | 探测死锁,不解锁 | read commit | 删除 |
8 | 探测死锁,不解锁 | repeatable read | 删除 |
1 innodb_lock_wait_timeout = 3 and innodb_deadlock_detect = OFF
innodb_deadlock_detect = OFF
innodb_lock_wait_timeout = 3
表的状态
mysql> select * from read_table;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
| 9 | 9 |
+----+------+
9 rows in set (0.00 sec)
1
2
3
4
这里我们可以看到,整体的操作中,隔离级别对于操作是没有任何影响的,结果都是一样,对于表中的锁定的数据更新失败。
innodb_deadlock_detect = ON
innodb_lock_wait_timeout = 86400
5
6
7
8
通过上面的几个实验,我们可以总结出以下一些结论
在MYSQL 配置中如果使用的 innodb_lock_wait_timeout =3 的配置的情况下,在很短的时间数据库就能判断出BLOCKED 或死锁,在这样的情况下,无论使用什么隔离级别,那么结果都是一样的,都会是锁超时的报错和让你重试的信息。
或者你使用了自动检测死锁,同时将innodb_lock_wait_timeout = 更大的数值,那么你得到的结果就与隔离级别有关了,如果是RR 的情况,你将会获得 update 0 的结果,如果是RC 数据还在的情况下,你会获得update 对应结果的结果,如果相关的行不在的情况下,获得结果也是UPDATE 0 的结果。
另这里也需要注意,在设置 innodb_lock_wait_timeout = 3 的情况下如果blocked 的情况不超过3秒,那么结果还是和 innodb_lock_wait_time=无限大的情况类似。
最终基于以上的结果,应用程序是需要针对程序最终在执行语句后的结果进行判断,到底是 update 0 还是 非0,并根据结果做出相关后续的操作。