mysql - 了解 InnoDB 锁定和事务模型

标签 mysql multithreading transactions innodb race-condition

最近我们讨论了如何解决竞争条件,我想知道在以下情况下我对 innodb 中的锁定和事务模型的理解是否正确(或者我可能遗漏的内容):

给定以下数据库表:

CREATE TABLE `requests` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `status` enum('queuing','processing') NOT NULL DEFAULT 'queuing',
  `pid` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

此表中有 3 个记录 r1、r2 和 r3(所有三个记录均处于排队状态且 pid = null)以及两个进程 P1 和 P2。

P1 运行以下查询,将下一个队列条目分配给自己。

UPDATE requests SET status = 'processing', pid = '1' 
WHERE status = 'queuing' 
AND pid IS NULL 
ORDER BY id 
LIMIT 1;

这将为 r1 中的 T1 设置独占记录锁。

现在 P2 运行更新查询

UPDATE requests 
SET status = 'processing', pid = '2' 
WHERE status = 'queuing' 
AND pid IS NULL 
ORDER BY id 
LIMIT 1;

并请求 r1 的独占记录锁。由于当前由 T1 持有,因此不会将锁授予 T2 -> T2 等待 T1 提交

P1 运行

SELECT * FROM requests WHERE status = 'processing' AND pid = '1';

并获取r1。 P1 提交 T1,并且对 r1 所做的更改对每个人都可见。

T2 继续,并且由于 r1 现在具有状态处理且 pid != null,因此为 r2 运行更新。 P2 选择 r2 并提交事务 T2 - 对 r2 所做的更改对每个人都可见。

感谢您的帮助。

最佳答案

我不会回答所提出的问题,而是要解决根本问题:“这把锁给我带来了麻烦;我该怎么办?”

INDEX(status, pid, id)

可能发生的情况是您必须在表中扫描相当远的距离,同时阻止其他人。有了这个索引,它应该能够更快地从 BTree 向下钻取到下一个项目。 “更快”意味着死锁的可能性更小。

一个缺点是新索引需要困惑的更新。

我的座右铭是“不要排队,只管去做”。我的意思是,在 MySQL 中构建排队机制的开销可能比 yield 更多。

此外,在自己的事务中运行 UPDATE,而不是某个更大代码块的一部分。

关于mysql - 了解 InnoDB 锁定和事务模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48425064/

相关文章:

hibernate - JPA 事务的工作原理

c# - 查询在 HeidiSQL 中有效,但在 C# 中失败

php - 将新语言名称插入到 codeigniter 中的数据库后,在语言文件夹中创建包含嵌套 php 文件的文件夹

c++ - libmysqlclient 竞争条件

java多线程模板基准测试

database - 让joomla使用innoDB并支持事务

mysql - 如何在 MYSQL 中提高批量插入的性能

c - 四线程分割进程C程序中的"Segmentation fault: 11"错误

c++ - 警告 : wint to poiter cast

java - 是否可以在 Spring AOP 建议中使用事务?