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

Редактировал(а) Alexandr Fokin 2025/09/20 11:33

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