mysql - 通过显式排序避免死锁

标签 mysql sql locking innodb pessimistic-locking

我想明确地提供一个关于 MySql InnoDB 应该如何获取行锁的顺序。如果这是可能的,就不应该有任何死锁只是拖延。 (如果我们遵循惯例。)

首先,数据库应该按升序锁定在表“models”中找到的所有行。然后第二个表“colors”中的所有行都应该按升序锁定。有没有办法控制数据库先锁定表“模型”,然后再锁定“颜色”?

例如:

start transaction;
select *
from models m
join colors c on c.model_id = m.id
where c.id IN (101, 105, 106)
order by m.id asc, c.id asc
for update;

最佳答案

虽然您可以通过 straight_join 来实现,但您也可以通过复制 select ...for update 来显式锁定您想要的行。

CREATE TEMPORARY TABLE colorsToUpdate (
     colorID BIGINT(20) NOT NULL, 
     modelID BIGINT(20) NOT NULL
);

insert into colorsToUpdate ( colorID, modelID)
SELECT  id, model_id
FROM    colors
where id in (101, 105, 106);

#This will try to acquire lock on models
select m.* from models m
join colorsToUpdate c
on c.modelID = m.id
for UPDATE;

#this will try to get locks on models, and colors.
select m.*, c.*
from colorsToUpdate u
left join models m
on u.modelID = m.id
join colors c 
on u.colorID = c.ID
order by m.id asc, c.id asc
for update;

# do your data modification here.

drop table colorsToUpdate;

由于锁定是在多个步骤中完成的,所以在您设置临时表和完成对两个表的锁定之间,表“colors”中的条目可能会被修改。

这对您来说可能没问题(即,如果您只想在事务开始时修改现有条目),但如果这不是您想要的,则可能会导致细微的错误。

关于mysql - 通过显式排序避免死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10838517/

相关文章:

mysql - 删除 hive 直线中的重复 header

mysql - Sequelize 中的 findAll() 找不到在事务中创建的行

sql - 数据库脚本按版本打包

java - 在以下上下文中如何确保线程安全?

java - 为什么我使用eclipse可以成功连接MySQL 8.0.13,但在cmd模式下却失败? (我的Java JDK是11.0.1)

php - MySQL异步数据库请求性能

php - php 5.6 中的 mysql 问题未选择数据库

用于获取最近价格变化最多的前 1 个产品的 SQL 查询

database - 为什么树协议(protocol)没有死锁?

c++ - 轻量级包装器 - 这是一个常见问题吗?如果是,它的名称是什么?