basic SQL atomicity " UPDATE ... SET. ГДЕ …"
У меня есть довольно основной и общий вопрос об атомарности "обновления ... НАБОР.. ГДЕ..." заявление.
Имея таблицу (без дополнительных ограничений),
+----------+
| id | name|
+----------+
| 1 | a |
+----+-----+
Теперь я бы выполнил следующие 4 утверждения "одновременно" (одновременно).
UPDATE table SET name='b1' WHERE name='a'
UPDATE table SET name='b2' WHERE name='a'
UPDATE table SET name='b3' WHERE name='a'
UPDATE table SET name='b4' WHERE name='a'
Существует ли только один оператор UPDATE, который будет выполняться с обновлением таблицы? или, возможно ли, что несколько инструкций UPDATE действительно могут обновить таблицу?
Должен ли я нуждаться в дополнительной транзакции или блокировке, чтобы позволить только одно обновление записывает значения в таблицу?
Спасибо
[править] 4 Инструкции UPDATE выполняются параллельно из разных процессов. [EDIT] with Postgresql
7 ответов:
Один из этих операторов заблокирует запись (или страницу, или всю таблицу, в зависимости от вашего движка и детализации блокировки) и будет выполнен.
Остальные будут ждать, пока ресурс освободится.Когда оператор lucky зафиксирует, остальные либо перечитают таблицу и ничего не сделают (если ваш режим изоляции транзакций установлен в
READ COMMITTED
), либо не смогут сериализовать транзакцию (если уровень изоляции транзакций равенSERIALIZABLE
).
Если вы запустили эти обновления на одном дыхании, он будет запускать их по порядку, поэтому он обновит все до b1, но тогда другие 3 не смогут обновить ни одного, так как не останется A для обновления.
Вокруг каждого будет существовать неявная транзакция, которая будет содержать другие обновления в очереди. В этом случае выиграет только первый, так как каждое последующее обновление не будет видеть имя, называемое "а".
Edit: я предполагал, что вы вызываете каждое обновление из отдельных процессов. Если бы они вызывались в одном скрипте, то выполнялись бы последовательно в порядке появления.
Существует только один оператор UPDATE, который может получить доступ к записи. Перед запуском он запускает транзакцию и блокирует таблицу (точнее, страницу, на которой находится запись, или даже только саму запись - это зависит от многих факторов). Затем он вносит изменения и снова разблокирует таблицу, фиксируя транзакцию в процессе.
Обновления / удаления / вставки в определенную запись являются однопоточными по самой своей природе, это необходимо для обеспечения целостности таблицы. Это не значит, что что обновления многих записей (которые находятся на разных страницах) не могут выполняться параллельно.
С заявлением, которое вы опубликовали, и вы закончите с ошибкой, потому что после первого обновления " a " не может быть найден. Чего вы пытаетесь этим добиться?
Даже если вы не задаете
begin transaction
иcommit transaction
, один оператор SQL всегда является транзакционным. Это означает, что только одно из обновлений может изменять строку одновременно. Остальные запросы будут блокироваться наupdate lock
, принадлежащем первому запросу.
Я думаю, что это может быть то, что вы ищете (в T-SQL):
UPDATE [table] SET [table].[name] = temp.new_name FROM [table], ( SELECT id, new_name = 'B'+ cast(row_number() over (order by [name]) as varchar) FROM [table] WHERE [table].name = 'A' ) temp WHERE [table].id = temp.id
Должна быть эквивалентная функция row_number в других вариантах SQL.