Как говорит brb tea, это зависит от реализации базы данных и используемого алгоритма: MVCC или двухфазная блокировка.
CUBRID (СУБД с открытым исходным кодом) объясняет идею этих двух алгоритмов:
- Двухфазная блокировка (2PL)
Первый - когда транзакция T2 пытается изменить запись A, она знает, что транзакция T1 уже изменила запись A, и ждет, пока транзакция T1 не будет завершена, потому что транзакция T2 не может знать, будет ли транзакция T1 зафиксирована или откатана. назад. Этот метод называется двухфазной синхронизацией (2PL).
- Управление многоверсионным параллелизмом (MVCC)
Другой - разрешить каждой из них, транзакциям T1 и T2, иметь свои собственные измененные версии. Даже когда транзакция T1 изменила запись A с 1 на 2, транзакция T1 оставляет исходное значение 1 как есть и записывает, что версия транзакции T1 записи A равна 2. Затем следующая транзакция T2 изменяет запись A. от 1 до 3, а не от 2 до 4, и пишет, что версия транзакции T2 для записи A - 3.
Когда транзакция T1 откатывается, не имеет значения, применяется ли 2, версия транзакции T1, к записи A. После этого, если транзакция T2 будет зафиксирована, 3, версия транзакции T2, будет применена к записи A. Если транзакция T1 фиксируется до транзакции T2, запись A изменяется на 2, а затем на 3 во время фиксации транзакции T2. Окончательный статус базы данных идентичен статусу выполнения каждой транзакции независимо, без какого-либо влияния на другие транзакции. Следовательно, он удовлетворяет свойству ACID. Этот метод называется контролем одновременного выполнения нескольких версий (MVCC).
MVCC допускает одновременные модификации за счет увеличения накладных расходов в памяти (поскольку он должен поддерживать разные версии одних и тех же данных) и вычислений (на уровне REPETEABLE_READ вы не можете потерять обновления, поэтому он должен проверять версии данных, например Hiberate делает с блокировкой Optimistick ).
В 2PL уровень изоляции транзакций контролирует следующее :
Принимаются ли блокировки при чтении данных и какой тип блокировки запрашивается.
Как долго удерживаются блокировки чтения.
Изменена ли операция чтения со ссылками на строки другой транзакцией:
Блокировать, пока исключительная блокировка строки не будет освобождена.
Получите зафиксированную версию строки, которая существовала на момент запуска оператора или транзакции.
Прочтите незафиксированную модификацию данных.
Выбор уровня изоляции транзакции не влияет на блокировки, которые используются для защиты изменений данных. Транзакция всегда получает монопольную блокировку любых данных, которые она изменяет, и удерживает эту блокировку до завершения транзакции, независимо от уровня изоляции, установленного для этой транзакции. Для операций чтения уровни изоляции транзакции в первую очередь определяют уровень защиты от изменений, внесенных другими транзакциями.
Более низкий уровень изоляции увеличивает возможность доступа многих пользователей к данным одновременно, но увеличивает количество эффектов параллелизма , таких как грязное чтение или потерянные обновления, с которыми могут столкнуться пользователи.
Конкретные примеры связи между блокировками и уровнями изоляции в SQL Server (используйте 2PL, кроме READ_COMMITED с READ_COMMITTED_SNAPSHOT = ON)
READ_UNCOMMITED: не применять разделяемые блокировки для предотвращения изменения данных, считываемых текущей транзакцией, другими транзакциями. READ UNCOMMITTED транзакции также не блокируются эксклюзивными блокировками, которые не позволят текущей транзакции читать строки, которые были изменены, но не зафиксированы другими транзакциями. [...]
READ_COMMITED:
- Если READ_COMMITTED_SNAPSHOT установлен в OFF (по умолчанию): использует разделяемые блокировки, чтобы предотвратить изменение строк другими транзакциями, пока текущая транзакция выполняет операцию чтения. Совместно используемые блокировки также блокируют чтение оператором строк, измененных другими транзакциями, до тех пор, пока другая транзакция не будет завершена. [...] Блокировки строк снимаются до обработки следующей строки. [...]
- Если READ_COMMITTED_SNAPSHOT имеет значение ON, компонент Database Engine использует управление версиями строк, чтобы представить каждому оператору согласованный с транзакционной точки зрения моментальный снимок данных в том виде, в каком он существовал в начале оператора. Блокировки не используются для защиты данных от обновлений другими транзакциями.
REPETEABLE_READ: общие блокировки устанавливаются на все данные, считываемые каждым оператором в транзакции, и удерживаются до завершения транзакции.
SERIALIZABLE: блокировки диапазона помещаются в диапазон значений ключа, который соответствует условиям поиска каждого оператора, выполняемого в транзакции. [...] Блокировки диапазона удерживаются до завершения транзакции.