Как стать автором
Обновить

Комментарии 8

Вы пишите, что аномалия «потерянное обновление» возможна только на уровнях изоляции READ UNCOMMITTED и READ COMMITTED. Также вы пишите, что на уровне изоляции REPEATABLE READ никто параллельно не может изменять или удалять строки, которые транзакция уже прочитала. Значит ли это, что REPEATABLE READ запрещает не только запись, но и чтение? Иначе я не понимаю, как этот уровень защищает от такого состояния гонки:

-- Транзакция 1
START TRANSACTION;
SELECT balance FROM users WHERE id = 1;
-- Возвращает 100

-- Транзакция 2 (исполняется параллельно другим процессом)
START TRANSACTION;
SELECT balance FROM users WHERE id = 1;
-- Возвращает 100

-- Транзакция 1
UPDATE users SET balance = 100+10 WHERE id = 1;
COMMIT;
-- Пополнение баланса потеряется из-за следующего выражения

-- Транзакция 2
UPDATE users SET balance = 100+15 WHERE id = 1;
COMMIT;

Понятно, что конкретно этот пример можно исправить, написав атомарное изменение баланса за 1 запрос. Но мне интересна именно такая форма транзакции, чтобы лучше понять, как работает изоляция.

P.S. Понравилось, как вы демонстрируете параллельные транзакции в статье.

Вторая транзакция заблокируется на `SELECT balance...`, пока первая не сделает commit/rollback.
REPEATABLE READ блокирует любой доступ к строке, пока транзакция лок не отпустит.
То, что у вас описано (`пополнение баланса потеряется из-за следующего выражения`) - это READ COMMITED

Значит, REPEATABLE READ запрещает не только запись, но и чтение. То есть в статье недоработка. Спасибо.

ну, там же вариантов, собственно, как вы заметили, не особенно много. Либо блочить строку целиком, либо ронять одну из транзакций. Вариант, когда каждая вторая транзакция фейлится - ну, такой себе. Поэтому просто блочат и запись, и чтение.

В случае с serializable происходит ровно то же самое, но на уровне таблицы целиком. Т.е. там вся таблица блочится, пока транзакция открыта.

Скриншоты весьма плохо читаемы. Гораздо разумнее отформатировать текст в две колонки. Ну или хотя бы сделать скрины чёрным по светло-серому.

Также считаю совершенно необходимым дать подготовительный код, который позволит читателю сразу начать воспроизведение показанных примеров (т.е. CREATE TABLE и начальный INSERT INTO). И укажите точно, какую СУБД (включая версию, хотя бы мажор) и даже какого клиента вы используете.

Показывая примеры на скриншотах, добавьте в начало операторы, которые явно устанавливают указанный уровень изоляции.

А если вторая транзакция откатит изменения и я опять сделаю SELECT к балансу, то я получу уже старый баланс.

А почему ЭТО не показано на скриншотах?

И очень хочется спросить - почему абсолютно все, и вы в том числе, рассматриваете только случаи, когда уровень изоляции транзакций обоих клиентов совпадает? У вас выпадает, по моему мнению, достаточно важный кусок понимания...

Изучить уровни изоляции транзакций не сложно - можно просто создать на сервере две таблицы и поставить сотню экспериментов в разных уровнях изоляции.
Честно скажу, у меня руки не дошли это проделать.
При этом все объяснения уровней изоляции для меня имеют один общий недостаток: не объясняется что происходит (или может происходить) внутри и соответственно невозможно ответить на вопрсы что будет если сталкиваются две транзакции с разными уровнями изоляции.

Спасибо, добавил раздел про параллельную работу транзакций с разными уровнями (хотя бы пару тезисов, о которых известно).

Упоминание уровней изоляции согласно стандарту SQL без учёта дырявости их концепции, открытом ещё в 90-х, резко неполно.

https://www.cockroachlabs.com/docs/stable/demo-serializable.html
http://justinjaffray.com/what-does-write-skew-look-like/
https://habr.com/ru/articles/705332/
https://habr.com/ru/company/otus/blog/501294/
https://habr.com/ru/articles/745948/
и прочая.

По сравнению с этим, данная статья всё-таки слишком примитивна.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории