Подтвердить что ты не робот

Как производить phantom чтение?

Используя "повторяемое чтение", должно быть возможно выполнить чтение phantom, но как? Мне нужно это для примера обучения студентов CS.

Я думаю, что я должен сделать "SELECT... WHERE x <= 888" в неиндексированном поле x, с верхним пределом 888 нет, а затем на другом соединении вставить новую строку со значением чуть ниже 888.

Кроме того, это не сработает. Нужен ли мне очень большой стол? Или что-то еще?

4b9b3361

Ответ 1

Эрик,

Я пришел просто из теста с очень большим количеством строк.

Вы никогда не найдете фантомы в mysql InnoDB с прочитанным или более ограниченным уровнем изоляции. Это объясняется документацией:

REPEATABLE READ: для последовательных чтений существует существенное отличие от уровня изоляции READ COMMITTED: все согласованные чтения в рамках одной транзакции считывают моментальный снимок, созданный с помощью первого прочитанного. Это соглашение означает, что если вы выдаете несколько простых (неблокирующих) операторов SELECT в рамках одной транзакции, эти операторы SELECT также согласуются друг с другом. См. Раздел 13.6.8.2, "Согласованные неблокирующие чтения".

Но вы также не можете найти фантомы в прочитанном фиксированном уровне изоляции: это необходимо, потому что "phantom rows" должен быть заблокирован для репликации и восстановления MySQL для работы.

Более подробная информация: http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html

Думаю, вам нужно будет перейти на другой бренд базы данных, чтобы показать фантомы своим ученикам. Я использую MSSQLSERVER и Oracle.

Хорошо... его жаль на ваш первый вопрос.

Ответ 2

Возможность воспроизведения phantom читает для движка InnoDB для уровня изоляции REPEATABLE READ сомнительно, потому что InnoDB использует Multiversion concurrency control - для каждой строки двигатель MVCC знает номера транзакций, когда строка была вставлена ​​и удалена, и может воспроизводить историю обновлений строк.

Таким образом, все последующие операторы SELECT будут отображать состояние таблицы в начале транзакции, за исключением строк, которые были вставлены, удалены или обновлены одной и той же транзакцией. Никакие новые строки, совершенные другими транзакциями, не появятся, потому что у них будут номера транзакций ввода, превышающие число транзакций этой транзакции, и диапазон строк не имеет значения.

Я смог воспроизвести phantom READS для уровня изоляции REPEATABLE READ для Apache Derby, потому что он не используйте multiversion concurrency control (версия 10.8.2.2 в момент написания этого ответа).

Чтобы воспроизвести, установите правильный уровень транзакции (в ij - Derby SQL-клиент):

-- Set autocommit off
autocommit off;
-- Set isolation level corresponding to ANSI REPEATABLE READ
set isolation rs;

Т1:

SELECT * FROM TableN;

Т2:

INSERT INTO TableN VALUES(55, 1);
COMMIT;

T1 снова:

SELECT * FROM TableN;

Теперь T1 должен увидеть еще одну строку;

Ответ 3

InnoDB должен защищать от чтения phantom, как писали другие.

Но у InnoDB есть другое странное поведение, связанное с блокировкой. Когда запрос получает блокировку, он всегда получает блокировку самой последней версии строки. Поэтому попробуйте следующее

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

Затем в двух параллельных сеансах (откройте два окна терминала):

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

                                           SELECT * FROM foo;

 UPDATE foo SET val=35 WHERE i=3;

                                           SELECT * FROM foo;

Это должно показать val = 10, 20, 30 в обоих SELECT, так как REPEATABLE-READ означает, что второе окно видит только данные, которые существовали при его запуске.

Однако:

                                           SELECT * FROM foo FOR UPDATE;

Второе окно ожидает получения блокировки в строке 3.

COMMIT;

Теперь 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;

Ответ 4

Phantom чтение может происходить из-за отсутствия запретов диапазона, тогда пример (псевдокод):

Резьба1

Transaction 1

Update TableN set X=2 where X=1

wait(s1)
Select TableN where X=1

Commit 

thread2

Transaction 2:

insert into tableN(id, X) values(55,1)
commit;
notify(s1)

В wikipedia есть еще один пример phantom: Phantom Reads | wikipedia

Здесь важна синхронизация транзакций, вы можете использовать точки синхронизации.

EDIT Пример использования функции сна mysql (не проверен):


--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;

Ответ 5

Чтобы дополнить Дани хороший ответ, вы можете использовать Microsoft Sql Server, чтобы показать это поведение своим ученикам.

Сервер Sql показывает, что phantom читает на уровне повторяемости чтения, как указано в документации здесь.

Postgres подписывается на то же понятие, что и InnoDb, как описано здесь. В Postgres также нет чтения phantom в повторяемом чтении и, следовательно, также не подходит для вашей дидактической цели.

Sql Server предлагает еще один уровень изоляции, моментальный снимок, который делает то, что MySql InnoDb и Postgres делает в повторяемом чтении (которое представляет собой незакрепленную версию на основе версии повторяемого чтения без phantom, но не сериализуется).

Sql Server Express бесплатный, хотя вам нужен компьютер с Windows. Вы также можете получить учетную запись Windows Azure и показать это поведение в Sql Azure онлайн.

Ответ 6

"phantom read" в MySQL на уровне изоляции RR скрыт глубоко, но все же может воспроизвести его. Вот шаги:

  • создать таблицу ab (первичный ключ int, b int);

  • Прд1:
      начать;
      выберите * from ab;//пустой набор

  • Tx2:
      начать;
      вставить в значения ab (1,1);
      совершить;
  • Tx1:
      выберите * from ab;//пустой набор, ожидаемый phantom чтение отсутствует.
      update ab set b = 2 где a = 1;//1 затронутая строка.
      выберите * from ab;//1 строка. phantom читайте здесь!!!!
      фиксации;