Mil*_*šić 9 mysql innodb transactions isolation-level locks
启用了InnoDB插件的MySQL Server版本5.1.41.我有以下三张发票表:发票,invoice_components和invoice_expenses.表发票具有invoice_id主键.invoice_components和invoice_expenses都链接到表发票,其invoice_id为非唯一foreign_key(每张发票可以包含多个组件和多个费用).两个表都具有此外键的BTREE索引.
我有以下交易:
交易1
START TRANSACTION;
SELECT * FROM invoices WHERE invoice_id = 18 FOR UPDATE;
SELECT * FROM invoice_components WHERE invoice = 18 FOR UPDATE;
SELECT * FROM invoice_expenses WHERE invoice = 18 FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)
对于第一个事务,一切正常,并且选择并锁定行.
交易2
START TRANSACTION;
SELECT * FROM invoices WHERE invoice_id = 19 FOR UPDATE;
SELECT * FROM invoice_components WHERE invoice = 19 FOR UPDATE;
SELECT * FROM invoice_expenses WHERE invoice = 19 FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)
第二个事务返回ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction第三个查询.
当我尝试SELECT ... FOR UPDATE其他发票及其组件和费用时也会发生同样的情况.似乎第一个事务已锁定invoice_expenses表中的所有行.任何想法为什么会这样?
附加信息
事务2在事务1的第三个查询之后开始.服务器上没有其他用户,连接或事务.
问题出现在默认的REPEATABLE READ事务隔离级别.它通过更改为READ COMMITTED级别来修复.这是一个解决方案,但它仍然无法解释为什么发票问题发生在invoice_expenses而不是invoice_components.
ype*_*eᵀᴹ 10
我怀疑它与间隙锁和下一键锁以及REPEATABLE READ行为的差异有关:
摘录来自MySQL文档:SET TRANSACTION语法
对于锁定读取(使用FOR UPDATE或LOCK IN SHARE MODE的SELECT),UPDATE和DELETE语句,锁定取决于语句是使用具有唯一搜索条件的唯一索引还是范围类型搜索条件.对于具有唯一搜索条件的唯一索引,InnoDB仅锁定找到的索引记录,而不是之前的间隙.对于其他搜索条件,InnoDB使用间隙锁或下一键(间隙加索引记录)锁来锁定扫描的索引范围,以阻止其他会话插入范围所覆盖的间隙.
和READ COMMITTED:
注意:在MySQL 5.1中,如果使用了READ COMMITTED隔离级别或启用了innodb_locks_unsafe_for_binlog系统变量,则除了外键约束检查和重复键检查外,没有InnoDB间隙锁定.此外,在MySQL评估WHERE条件后,将释放非匹配行的记录锁.
也许OP可以告诉我们innodb_locks_unsafe_for_binlog system变量的状态以及当变量的设置被更改时是否发生相同的锁定.
此外,如果相同的锁定发生在没有连续的id,例如18和20,或者18和99
小智 -2
您正在使用交易;自动提交不会禁用事务,它只是使事务在没有显式声明的语句末尾自动提交start transaction。
发生的情况是,其他一些线程在某些记录上持有记录锁(您正在更新表中的每条记录!)太长时间,并且您的线程超时。
您可以通过在事件发生后发出“SHOW ENGINE INNODB STATUS”来查看事件的更多详细信息。最好在安静的测试机上进行此操作。
| 归档时间: |
|
| 查看次数: |
7275 次 |
| 最近记录: |