Исходный код вики Примеры.

Версия 1.34 от Alexandr Fokin на 2025/09/20 11:04

Скрыть последних авторов
Alexandr Fokin 1.10 1 (% style="width:1426px" %)
2 |(% style="width:155px" %)**Необходимый уровень изоляции**|(% style="width:614px" %)**Запрос**|(% style="width:652px" %)**Комментарий**
Alexandr Fokin 1.18 3 |(% style="width:155px" %) |(% style="width:614px" %) |(% style="width:652px" %)Замечание: в приведенных ниже примерах не рассматриваются сценарии с использованием [[Оптимистичная блокировка>>doc:Архитектура и модели.Блокировки.Оптимистичная блокировка.WebHome]].
Alexandr Fokin 1.33 4 Механизмы БД и [[Пессимистичная блокировка>>doc:Архитектура и модели.Блокировки.Пессимистичная блокировка.WebHome]].
Alexandr Fokin 1.9 5 |(% style="width:155px" %)READ COMMITTED|(% style="width:614px" %){{code language="sql"}}BEGIN;
Alexandr Fokin 1.1 6
Alexandr Fokin 1.34 7 -- Проверка
8
Alexandr Fokin 1.2 9 UPDATE accounts
10 SET balance = balance + @payment
11 WHERE acctnum = @account1
Alexandr Fokin 1.1 12
Alexandr Fokin 1.2 13 UPDATE accounts
14 SET balance = balance - @payment
Alexandr Fokin 1.11 15 WHERE acctnum = @account2
Alexandr Fokin 1.1 16
Alexandr Fokin 1.10 17 COMMIT;{{/code}}|(% style="width:652px" %)(((
Alexandr Fokin 1.7 18 * Относительное изменения значения (а не константное).
19 * Без проверок.
Alexandr Fokin 1.32 20
Alexandr Fokin 1.33 21 (В данном случае строка заблокируется в момент обновления (update). Чтение (select) с проверкой условия без явного указания updatelock не будет удерживать блокировку, строка может быть изменена после проверки условия).
Alexandr Fokin 1.7 22 )))
Alexandr Fokin 1.26 23 |(% style="width:155px" %)REPEATABLE READ|(% style="width:614px" %)(((
Alexandr Fokin 1.29 24 |MSSQL|{{code language="sql"}}SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
25 BEGIN TRANSACTION
Alexandr Fokin 1.2 26
Alexandr Fokin 1.29 27 if (SELECT balance FROM accounts /*FOR UPDATE*/ where acctnum = @account2 ) < @payment
Alexandr Fokin 1.34 28 -- error
Alexandr Fokin 1.26 29 END IF
30
31 UPDATE accounts
32 SET balance = balance + @payment
33 WHERE acctnum = @account1
34
35 UPDATE accounts
36 SET balance = balance - @payment
37 WHERE acctnum = @account2
38
39 COMMIT;{{/code}}|
Alexandr Fokin 1.30 40 |Postgres|{{code language="sql"}}BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Alexandr Fokin 1.26 41
42 if (SELECT balance FROM accounts where acctnum = @account2 ) < @payment
Alexandr Fokin 1.1 43 RAISE EXCEPTION ''
44 END IF
45
Alexandr Fokin 1.2 46 UPDATE accounts
47 SET balance = balance + @payment
48 WHERE acctnum = @account1
Alexandr Fokin 1.1 49
Alexandr Fokin 1.2 50 UPDATE accounts
51 SET balance = balance - @payment
Alexandr Fokin 1.11 52 WHERE acctnum = @account2
Alexandr Fokin 1.1 53
Alexandr Fokin 1.26 54 COMMIT;{{/code}}|
55 | | |
56 )))|(% style="width:652px" %)(((
Alexandr Fokin 1.7 57 * Предварительная проверка условия перед изменением строк.
Alexandr Fokin 1.14 58 Гарантия, что значение не будет изменено другими транзакциями после проверки (или их изменение будет обнаружено и приведет к ошибке).
59 * В запросе могут использоваться как относительные, так и константные значения, при условии что значение было сформировано после проверки допустимости операции.
Alexandr Fokin 1.15 60
Alexandr Fokin 1.33 61 (В данном случае чтение (select) удерживает share блокировку, что гарантирует, что строка не будет изменена. Но параллельный переход от sharelock к updatelock приводит к deadlock, поэтому может быть лучше сразу накладывать updatelock).
Alexandr Fokin 1.32 62
Alexandr Fokin 1.15 63 ----
64
Alexandr Fokin 1.33 65 Данное поведение также может быть реализовано на уровне READ COMMITTED, но для этого нужно явно выполнять чтение с updatelock.
Alexandr Fokin 1.17 66 (Причем для данного примера явная блокировка была бы обязательна только для проверяемого аккаунта, с которого выполняется списание).
Alexandr Fokin 1.7 67 )))