对于隔离级别REPEATABLE READ,InnoDB引擎重现幻像读取的可能性值得怀疑,因为InnoDB使用Multiversion concurrency control-对于每一行,MVCC引擎知道插入和删除行时的事务号,并且可以重现行更新历史。 因此,所有后续SELECT语句都将在事务开始时显示表的状态,但由同一事务插入、删除或更新的行除外。不会出现由其他事务提交的新行,因为它们的插入事务号将大于此事务的插入事务号,并且行的范围在此无关紧要。 我能够为Apache Derby数据库再现隔离级别REPEATABLE READ的幻像读取,因为它不使用多版本并发控制(在编写本答案时版本为www.example.com)。10.8.2.2 in the moment of writing of this answer). 要重现,请设置适当的事务级别(在ij-Derby的SQL客户端中):
-- Set autocommit off
autocommit off;
-- Set isolation level corresponding to ANSI REPEATABLE READ
set isolation rs;
Transaction 1
Update TableN set X=2 where X=1
wait(s1)
Select TableN where X=1
Commit
线程2
Transaction 2:
insert into tableN(id, X) values(55,1)
commit;
notify(s1)
在维基百科还有另一个例子幻影读:体模读数|维基百科 这里重要的是事务同步,您可以使用同步点。
EDIT使用mysql sleep函数的示例(未测试):
``
--on thread 1
Create TableN(id int, x int);
insert into TableN(id, X) values(1,1);
insert into TableN(id, X) values(2,1);
insert into TableN(id, X) values(3,1);
BEGIN TRANSACTION;
Update TableN set X=2 where X=1
SELECT SLEEP(30) FROM DUAL;
select TableN from where X=1;
COMMIT;
--In other thread, before 20 secs;
BEGIN TRANSACTION;
insert into TableN(id, X) values(55,1);
COMMIT;
7条答案
按热度按时间x33g5p2x1#
RR隔离级别上MySQL中的"幻像读"隐藏得很深,但仍然可以重现,步骤如下:
1.创建表ab(a int主键,b int);
1.治疗1:
开始
从ab中选择 *;//空集
1.治疗2:
开始
插入ab值(1,1);
承诺;
1.治疗1:
从ab中选择 *;//空集,缺少预期的幻像读取。
更新ab,设置b = 2,其中a = 1;//1行受影响。
从ab中选择 *;//1行。在此处读取幻像!!!
承诺;
6jygbczu2#
艾瑞克
我刚从测试中得到它有非常多的行数。
在InnoDB mysql上,你永远不会找到带有read commited或更严格隔离级别的幻像。
可重复读取:对于一致性读取,与READ COMMITTED隔离级别有一个重要区别:同一事务中的所有一致读取都读取第一次读取建立的快照。此约定意味着,如果在同一事务中发出多个纯文本(非锁定)SELECT语句,则这些SELECT语句彼此之间也是一致的。请参见13.6.8.2“一致的非锁定读取”一节。
但您无法在已提交读取的隔离级别中找到幻像:这是必要的,因为必须阻止“幻像行”才能使MySQL复制和恢复正常工作。
更多详细信息:http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html
我认为您将需要转移到另一个数据库品牌来向您的学生显示幻影。我同时使用MSSQLSERVER和Oracle。
嗯......很遗憾你的第一个问题。
ffvjumwh3#
InnoDB应该像其他人写的那样,防止幻像读取。
但是InnoDB有一个与锁相关的奇怪行为,当查询获取锁时,它总是获取行的最新版本的锁。
然后在两个并发会话中(打开两个终端窗口):
这应该在两个SELECT中显示val = 10、20、30,因为REPEATABLE-READ意味着第二个窗口只能看到事务开始时存在的数据。
然而:
第二个窗口等待获取行3上的锁。
现在,第二个窗口中的SELECT操作完成,并显示val = 10、20、35的行,因为锁定该行会使SELECT看到最新提交的版本。InnoDB中的锁定操作就像是在READ-COMMITTED下运行一样,而与事务的隔离级别无关。
您甚至可以来回切换:
ssm49v7z4#
对于隔离级别REPEATABLE READ,InnoDB引擎重现幻像读取的可能性值得怀疑,因为InnoDB使用Multiversion concurrency control-对于每一行,MVCC引擎知道插入和删除行时的事务号,并且可以重现行更新历史。
因此,所有后续SELECT语句都将在事务开始时显示表的状态,但由同一事务插入、删除或更新的行除外。不会出现由其他事务提交的新行,因为它们的插入事务号将大于此事务的插入事务号,并且行的范围在此无关紧要。
我能够为Apache Derby数据库再现隔离级别REPEATABLE READ的幻像读取,因为它不使用多版本并发控制(在编写本答案时版本为www.example.com)。10.8.2.2 in the moment of writing of this answer).
要重现,请设置适当的事务级别(在ij-Derby的SQL客户端中):
T1:
T2:
T1再次:
现在T1应该看到另一行;
hmtdttj45#
您可以在MySQL的**
REPEATABLE READ
中生成幻像读取**。首先,设置**
REPEATABLE READ
**:然后,使用**
id
和name
创建person
表格**,如下所示。person
表格:| 身份证|姓名|
| - ------|- ------|
| * * 一个**|"约翰"|
| * * 二**|* * 大卫**|
然后,执行以下步骤和MySQL查询。* 我使用了2个命令提示符:
| 流量|交易1(T1)|交易2(T2)|解释|
| - ------|- ------|- ------|- ------|
| * * 步骤1**|* * 一米六米一x**||* * T1启动。|
| * * 第二步||* * 一米七三**|* * T2启动。|
| * * 步骤3|* * 一米八米一x*** * 约翰一号*** * 2大卫**||* * T1读取2行。|
| * * 步骤4||* * 一米九十一**|* * T2将包含
3
和Tom
的行插入到person
表格中。|| * * 第五步||* * 一米十三十一x**|* * T2提交。|
| * * 第六步|* * 一米十四分一秒*** * 约翰一号*** * 2大卫**||* * T1在T2提交后读取2行。####* 暂时不会发生幻像读取!!|
| * * 第七步|* * 一米十五纳一x**||* * 令您惊讶的是,T1可以将T2刚刚插入的新行从
Tom
更新为Lisa
。|| * * 第8步|* * 1米18英寸1x*** * 约翰一号*** * 2大卫*** * 3丽莎**||* * 令您惊讶的是,T1在T2提交后读取了3行。####* 发生幻像读取!!|
| * * 第七步|* * 一米十九寸**||* * T1提交。|
此外,我在Postgresql中的
REPEATABLE READ
中执行了上述步骤,但没有发生幻像读取**。dced5bon6#
由于不存在范围锁,因此可能发生幻像读取,示例如下(伪代码):
螺纹1
线程2
在维基百科还有另一个例子幻影读:体模读数|维基百科
这里重要的是事务同步,您可以使用同步点。
EDIT使用mysql sleep函数的示例(未测试):
``
``
snz8szmq7#
为了补充Dani的正确答案,您可以使用Microsoft Sql Server向您的学生展示这种行为。
Sql Server显示了文档here中声明的可重复读取隔离级别中的幻像读取。
正如here所解释的那样,Postgres与InnoDb采用了相同的概念,在可重复读取中也不会发生幻像读取,因此也不适合您的教学目的。
Sql Server提供了另一个隔离级别,快照,它执行MySql InnoDb和Postgres在可重复读取中执行的操作(这是一种无锁、基于版本的可重复读取实现,没有幻像读取,但不可序列化)。
Sql Server Express是免费的,尽管你确实需要一台Windows计算机。你也可以为自己获得一个Windows Azure帐户,并在线显示Sql Azure的行为。