具有 innodb 和可序列化事务的 Mysql 不会(总是)锁定行

标签 mysql transactions innodb isolation-level

我有一个带有 SELECT 和可能的 INSERT 的交易。出于并发原因,我将 FOR UPDATE 添加到 SELECT。为了防止幻像行,我使用了 SERIALIZABLE 事务隔离级别。当表中有任何行时,这一切都可以正常工作,但如果表为空则不行。当表为空时,SELECT FOR UPDATE 不会执行任何(独占)锁定,并发线程/进程可以发出相同的 SELECT FOR UPDATE 而无需锁定。

CREATE TABLE t (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  display_order INT
) ENGINE = InnoDB;

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT COALESCE(MAX(display_order), 0) + 1 from t FOR UPDATE;

..

这个概念与 SQL Server 的预期一样有效,但不适用于 MySQL。对我做错了什么有什么想法吗?

编辑

在 display_order 上添加索引不会改变行为。

最佳答案

这有一些有趣的,两个事务都准备好获得真正的锁。一旦其中一个事务尝试执行插入,锁就会出现。如果两个事务都尝试它,一个将得到一个死锁并回滚。如果只有其中一个尝试,它将获得锁定等待超时

如果您检测到锁定等待超时,您可以回滚,这将允许下一个事务执行插入。

所以我认为您很可能会很快遇到死锁异常或超时异常,这应该可以挽救这种情况。但是谈到完美的“可序列化”情况,这实际上是空表的不良副作用。该引擎不可能在所有情况下都是完美的,至少不能完成双事务插入..

我昨天在 potsgreSQl 文档上发送了一个关于真正的可串行性与引擎可串行性的有趣案例,检查这个例子它有趣:http://www.postgresql.org/docs/8.4/static/transaction-iso.html#MVCC-SERIALIZABILITY

更新: 其他有趣的资源:Does MySQL/InnoDB implement true serializable isolation?

关于具有 innodb 和可序列化事务的 Mysql 不会(总是)锁定行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4668801/

相关文章:

php - Drupal 数据库性能调整 - 将特定表从 MyISAM 切换到 InnoDB

mysql - 向 mySQL 表插入几个字节 -> 180kB 写入磁盘

python - 将本地 infile csv 加载到 mysql 数据库失败

mysql - 单表层次结构的性能问题

javascript - 第二个下拉选择与第一个下拉选择的选择相关

c# - TransactionScope 在某些机器上自动升级到 MSDTC?

php - 在我的自定义表中,我希望有 15 天的差异才能从表中获取用户 ID。 Date_diff 函数无法正常工作?

python - 不是 Django 中 @atomic() 的嵌套版本?

database - 具有链式调用的 Grails 服务类的事务行为

sql - InnoDB 表从固定长度的行中获益多少?