базовая атомарность SQL "ОБНОВЛЕНИЕ ... УСТАНОВЛЕНО ... ГДЕ ..." - PullRequest
2 голосов
/ 19 апреля 2010

У меня довольно простой и общий вопрос об атомарности выражения "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 выполняются параллельно из разных процессов. [РЕДАКТИРОВАТЬ] с Postgresql

Ответы [ 7 ]

8 голосов
/ 19 апреля 2010

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

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

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

1 голос
/ 19 апреля 2010

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

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

1 голос
/ 19 апреля 2010

Вокруг каждой будет неявная транзакция, которая будет содержать другие ОБНОВЛЕНИЯ в очереди. В этом случае победит только первый, так как каждое последующее обновление не увидит имя с именем «a».

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

1 голос
/ 19 апреля 2010

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

0 голосов
/ 19 апреля 2010

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

В других разновидностях SQL должна быть функция, эквивалентная row_number.

0 голосов
/ 19 апреля 2010

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

0 голосов
/ 19 апреля 2010

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

...