2010-04-19 4 views
2

У меня есть довольно простой и общий вопрос об атомарности оператора «UPDATE ... SET .. WHERE ...».basic SQL atomicity «UPDATE ... SET .. WHERE ...»

имея таблицу (без дополнительных ограничений),

+----------+ 
| 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 может действительно обновить таблицу?

Должен ли я нуждаться в дополнительной транзакции или блокировке, чтобы только одно значение UPDATE записывало в таблицу?

благодарит

[EDIT] в 4 заявления UPDATE выполняются параллельно из различных процессов. [EDIT] с Postgresql

+3

После первого заявления никто из других ничего не сделает, так как вы изменили «имя» от * a * до * b1 *. – RedFilter

ответ

8

Одно из этих операторов блокирует запись (или страницу, или всю таблицу, в зависимости от вашего механизма и детализации) и будет выполнена.

Остальные будут ждать освобождения ресурса.

Когда повешение будет зафиксировано, другие либо перечитают таблицу, либо ничего не сделают (если в режиме изоляции транзакции установлено значение READ COMMITTED) или не удалось выполнить сериализацию транзакции (если уровень изоляции транзакции SERIALIZABLE).

0

С заявлением, которое вы отправили, и вы получите ошибку, потому что после первого обновления «a» не может быть найдено. Что вы пытаетесь достичь с этим?

+1

Не было бы ошибки: вы бы просто получили «0 строк, затронутых». –

1

Если вы запустили эти ОБНОВЛЕНИЯ за один раз, они будут запускать их по порядку, поэтому он обновит все до b1, а затем остальные 3 не смогут обновить их, так как не останется никаких левых для обновления.

1

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

Редактировать: Я предполагал, что вы вызывали каждый UPDATE из отдельных процессов. Если они были вызваны в одном скрипте, они будут выполняться последовательно в порядке появления.

1

Существует только один оператор UPDATE, который может получить доступ к записи. Перед запуском он начинает транзакцию и блокирует таблицу (или, вернее, страницу, на которой записана запись, или даже сама запись - это зависит от многих факторов). Затем он делает изменение и разблокирует таблицу снова, совершая транзакцию в этом процессе.

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

+0

"или, вернее, страница, на которой записана запись" - Не обязательно. В Oracle только строка заблокирована, а не целая страница. Это действительно зависит от базы данных. – dcp

+0

@dcp: Да, и по стратегии блокировки, которая действует, по любым подсказкам запроса и так далее. Моя точка зрения - это не обязательно блокировка всей таблицы. – Tomalak

0

Даже если вы не указали begin transaction и commit transaction, один оператор SQL всегда является транзакционным. Это означает, что только одно из обновлений позволяет изменять строку одновременно.Остальные запросы будут блокироваться на update lock, принадлежащем первому запросу.

0

Я считаю, что это может быть то, что вы ищете (в 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.

Смежные вопросы