不完全清楚MySQL文档InnoDB引擎是否实现真正可序列化的隔离_1或[_快照隔离]](...),这通常也被称为“可序列化”。是哪一个?
如果mysql InnoDB没有,是否有任何完全免费的、生产质量良好的RDBMS?
其中,“真正的可序列化隔离”不仅意味着没有按照sql标准读取异常,而且意味着没有写入倾斜异常,并将进一步详细解释。
发布于 2018-03-20 12:35:13
最新情况:
请看评论,这似乎是修正了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!
+-------+-------+
结果:通过在插入影响并行事务查询的行之前插入一个新的无关行,我们欺骗了下一个键锁定机制。或者至少这是我从测试中了解到的。所以我想说,不要相信引擎具有真正的可序列化性。...。当你有集料在事务中,最好的方法是手动执行。把表锁上,把你的可序列化问题转化成一个真正的只有一个人的情况,没有惊喜!示例中的其他可串行化问题是约束验证(检查操作后的数量是否仍为正),你是否也拥有这些情况的锁。
https://stackoverflow.com/questions/-100007685
复制相似问题