MySQL/InnoDB是否实现真正的可序列化隔离?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (27)

不完全清楚MySQL文档InnoDB引擎是否实现真正可序列化的隔离_1或[_快照隔离]](...),这通常也被称为“可序列化”。是哪一个?

如果mysql InnoDB没有,是否有任何完全免费的、生产质量良好的RDBMS?

其中,“真正的可序列化隔离”不仅意味着没有按照sql标准读取异常,而且意味着没有写入倾斜异常,并将进一步详细解释。

提问于
用户回答回答于

是否有任何完全免费的,生产质量的RDBMS,可以吗?

Postgres支持真正的可序列化隔离。从9.1版开始。它当然可以被称为“完全免费”和“生产质量”。

用户回答回答于

最新情况:

请看评论,这似乎是修正了mysql 5.5,使用这些示例,我们仍然有一个表锁,索引下键锁不能被愚弄,AFAIK。

原件:

昨天发现了你的问题,我也在想关于InnoDb的MVCC可串行化模型。

所以我做了一些试验...。MySQL 5.1.37。中提供的可序列化问题的测试是一个很好的测试。PostgreSQL 9.0 MVCC文档,关于这一章系列化隔离与真实可序列化性

所以让我们在MySQL上测试它:

CREATE TABLE t1 (
 class integer,
 value integer
) ENGINE=InnoDB;

INSERT INTO t1 (`class`,`value`) VALUES
  (1,10),
  (1,20),
  (2,100),
  (2,200);

现在,我们将打开两个不同的连接,以具有两个并行事务(T1和T2):

T1:

SET TRANSACTIOn ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(value) FROM t1 WHERE class = 1;

结果是30。

T2:

 SET TRANSACTIOn ISOLATION LEVEL SERIALIZABLE;
 BEGIN;
 SELECT SUM(value) FROM t1 WHERE class = 2;

结果是300。

T1:

INSERT INTO t1 (`class`,`value`) VALUES (2,30);

=>等待

T2:

INSERT INTO t1 (`class`,`value`) VALUES (1,300);

==>Error 1213(40001):尝试锁定时发现死锁;尝试重新启动事务

T1现在成功插入,T2有回滚,良好的系列化性...

这将在PostgreSQL 9.0上失败(情况在9.1上正在改变,但这是另一个问题)。事实上只有1交易可以执行插入在桌子上。即使我们试图插入class=3和。

INSERT INTO t1 (`class`,`value`) VALUES (3,30);

我们会看到一个等待的锁,和死锁,以防出现问题。看起来我们在MySQL中有一个谓词锁..。但事实上在InnoDB中实施。

Innodb执行行锁,并在索引上锁定一些空白。在这里,我们没有索引在表上,看起来MySQL决定锁定表。

因此,让我们试着测试下一个键锁定,看看这是否强制序列化。首先回滚正在运行的事务(T1)。然后创建一个索引。

CREATE index t1class ON t1 (class);

现在重新做测试。成功,可序列化性仍然被强制执行。好消息。

但是随着索引的建立,我认为下一个键锁定和行锁都是在索引上完成的。这意味着,如果插入不影响并行事务,我们应该能够执行插入。现在出现了一个大问题...

T1:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(value) FROM t1 WHERE class = 1;

结果是30。

T2:

 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
 BEGIN;
 SELECT SUM(value) FROM t1 WHERE class = 2;

结果是300。

在这里,我们将在T1上做一个不相关的插入,现在我们有了一个索引,这将成功:

T1:

INSERT INTO t1 (`class`,`value`) VALUES (3,30);

两者都可以执行插入(这里我只做了一个),这是正常的。没有应用预测锁定,因此没有对class=3...。看起来,如果我们给下一个键锁定好的索引(插入时没有表锁),那么下一个键锁定的性能会更好。

现在,我们尝试在下一个键锁上插入T2(class=2)的行匹配选择:

T1:

INSERT INTO t1 (`class`,`value`) VALUES (2,30);

成功

T2:

INSERT INTO t1 (`class`,`value`) VALUES (1,300);

=>等待。

T1:

COMMIT;

T2:(在锁已消失的地方,就会插入)

SELECT SUM(value) FROM t1 WHERE class = 2;
COMMIT;

这里还有300个。看来可系列化已经消失了。

select * from t1;
+-------+-------+
| class | value |
+-------+-------+
|     1 |    10 | 
|     1 |    20 | 
|     2 |   100 | 
|     2 |   200 | 
|     3 |    30 | <-- test
|     2 |    30 | <-- from trans1
|     1 |   300 | <-- from trans2 ERROR!
+-------+-------+

结果:通过在插入影响并行事务查询的行之前插入一个新的无关行,我们欺骗了下一个键锁定机制。或者至少这是我从测试中了解到的。所以我想说,不要相信引擎具有真正的可序列化性。...。当你有集料在事务中,最好的方法是手动执行。把表锁上,把你的可序列化问题转化成一个真正的只有一个人的情况,没有惊喜!示例中的其他可串行化问题是约束验证(检查操作后的数量是否仍为正),你是否也拥有这些情况的锁。

扫码关注云+社区