如何制作幻像读物?

Eri*_*rik 23 mysql sql database isolation-level

使用"可重复读取"应该可以产生幻像读取,但是如何?我需要它作为一个教学CS学生的例子.

我认为我必须在非索引字段x上创建"SELECT ... WHERE x <= 888",上限888不存在,然后在另一个连接上插入一个值低于888的新行.

除了它不起作用.我需要一张非常大的桌子吗?或者是其他东西?

dan*_*era 15

埃里克

我来自于测试它的行数非常多.

你永远不会在InnoDB mysql上发现有读取提交或更严格的隔离级别的幻像.它在文档中解释:

REPEATABLE READ:对于一致读取,与READ COMMITTED隔离级别有一个重要区别:同一事务中的所有一致读取读取第一次读取建立的快照.此约定意味着如果在同一事务中发出多个普通(非锁定)SELECT语句,则这些SELECT语句也相互一致.请参见第13.6.8.2节"一致的非锁定读取".

但是你也不能在read commited isolation level中找到幻像:这是必要的,因为必须阻止"幻像行"才能使MySQL复制和恢复工作.

更详细的信息:http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html

我认为您需要转移到另一个数据库品牌,以向您的学生展示幻影.我同时使用MSSQLSERVEROracle.

嗯...对你的第一个问题很可惜.


Col*_*ang 12

MySQL隔离级别的MySQL中的"幻像读取"隐藏得很深,但仍然可以重现它.以下是步骤:

  1. create table ab(一个int主键,b int);

  2. Tx1:
    开始;
    从ab中选择*; //空集

  3. Tx2:
    开始;
    插入ab值(1,1);
    承诺;
  4. Tx1:
    从ab中选择*; //空集,预期幻像读缺失.
    更新ab set b = 2其中a = 1; // 1行受影响
    从ab中选择*; // 1行 幻影在这里阅读!!!!
    承诺;

  • 希望能解释一下为什么会这样。不过很好的答案! (2认同)

Nul*_*ice 5

对于InnoDB引擎以隔离级别重现幻像读取的可能性,REPEATABLE READ值得怀疑,因为InnoDB使用Multiversion并发控制 -对于每一行,MVCC引擎在插入和删除行时都知道事务编号,并且可以重现行更新的历史记录。

因此,所有随后的SELECT语句将在事务开始时显示表的状态,但同一事务在同一行中插入,删除或更新的行除外。其他事务提交的新行将不会出现,因为它们将具有比该事务大的插入事务编号,并且行范围在这里无关紧要。

我能够为Apache Derby数据库的隔离级别REPEATABLE READ再现PHANTOM READS ,因为它不使用多版本并发控制(在编写此答案时为版本10.8.2.2)。

要重现,请设置适当的事务级别(在ij-Derby的SQL客户端中):

-- Set autocommit off
autocommit off;
-- Set isolation level corresponding to ANSI REPEATABLE READ
set isolation rs;
Run Code Online (Sandbox Code Playgroud)

T1:

SELECT * FROM TableN;
Run Code Online (Sandbox Code Playgroud)

T2:

INSERT INTO TableN VALUES(55, 1);
COMMIT;
Run Code Online (Sandbox Code Playgroud)

再次T1:

SELECT * FROM TableN;
Run Code Online (Sandbox Code Playgroud)

现在T1应该再看到一行;


Bil*_*win 5

InnoDB应该像其他人一样防止幻像读取。

但是InnoDB具有与锁定有关的另一种怪异行为。查询获取锁时,它总是获取行的最新版本的锁。所以尝试以下

CREATE TABLE foo (i INT PRIMARY KEY, val INT);
INSERT INTO foo (i, val) VALUES (1, 10), (2, 20), (3, 30);
Run Code Online (Sandbox Code Playgroud)

然后在两个并发会话中(打开两个终端窗口):

-- window 1                               -- window 2
START TRANSACTION;
                                          START TRANSACTION;

                                           SELECT * FROM foo;

 UPDATE foo SET val=35 WHERE i=3;

                                           SELECT * FROM foo;
Run Code Online (Sandbox Code Playgroud)

这应该在两个SELECT中都显示val = 10、20、30,因为REPEATABLE-READ表示第二个窗口仅看到事务开始时存在的数据。

然而:

                                           SELECT * FROM foo FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)

第二个窗口等待获取对第3行的锁定。

COMMIT;
Run Code Online (Sandbox Code Playgroud)

现在,第二个窗口中的SELECT完成,并显示val = 10、20、35的行,因为锁定该行会导致SELECT查看最新提交的版本。无论事务的隔离级别如何,InnoDB中的锁定操作都像在READ-COMMITTED下运行一样。

您甚至可以来回切换:

                                           SELECT * FROM foo;

                                           SELECT * FROM foo FOR UPDATE;

                                           SELECT * FROM foo;

                                           SELECT * FROM foo FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)