Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle
.pdfПример 43: управление уровнем изолированности транзакций
|
:.1.a |
|
1 |
COMMIT; |
|
2 |
SELECT SYS_CONTEXT('userenv', 'sessionid') |
|
3 |
FROM DUAL; |
|
4 |
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
|
5 |
SELECT "sb finish" |
|
6 |
FROM "subscriptions" ORDER BY |
"sb_finish" ASC; |
7— EXEC DBMS_LOCK.SLEEP(10);
8COMMIT;
Раскомментировав строку с EXEC DBMS_LOCK.SLEEP(10) в соответствую-
щем блоке кода, мы проэмулируем его долгое выполнение, что позволит нам не спеша несколько раз выполнить второй блок (в котором эта строка останется закомментированной) и посмотреть на результат.
На этом решение данной задачи завершено.
•Ч Решение 6.2.1. b 4 .
Решение данной задачи подчиняется общей логике разделения уровней изолированности транзакций:
•чем уровень ниже, тем больше у СУБД возможностей выполнить запрос параллельно с другими, но тем выше вероятность получить некорректный результат;
•чум уровень выше, тем меньше у СУБД возможностей выполнить запрос параллельно с другими, но тем ниже вероятность получить некорректный результат;
•в MySQL и MS SQL Server самым низким уровнем является READ UNCOM-
MITTED, в Oracle — READ COMMITTED;
• во всех трёх СУБД самым высоким уровнем является SERIALIZABLE.
Учитывая эти факты, нам остаётся только написать код для выполнения одного и того же запроса на самом низком и самом высоком уровнях изолированности транзакций, а также подготовить проверочный код, который позволит увидеть разницу в работе этих двух вариантов выполнения основного кода.
Код для MySQL выглядит следующим образом.
MySQL I |
Решение 6.2.1.b (максимально быстрое выполнение, возможны некорректные данные) |
| |
|||
1 |
SELECT CONNECTION_ID(); |
|
|
||
2 |
SET autocommit = 0; |
|
|
||
3 |
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|
|||
4 |
START |
TRANSACTION; |
|
|
|
5 |
SELECT 'sb subscriber', |
|
|
||
6 |
|
|
COUNT('sb book') |
AS 'sb has books' |
|
7 |
FROM |
|
'subscriptions' |
|
|
8 |
WHERE |
'sb is active' = |
'Y' |
|
|
9 |
GROUP |
BY 'sb_subscriber ; |
|
||
10 |
COMMIT ; |
|
|
||
|
|
|
|
||
|
|
|
|
||
MySQL I |
|
Решение 6.2.1.b (максимально корректные данные, возможно долгое выполнение) |
| |
||
1 |
SELECT CONNECTION_ID(); |
|
|
||
2 |
SET autocommit = 0; |
|
|
||
3 |
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; |
|
|||
4 |
START |
TRANSACTION; |
|
|
|
5 |
SELECT 'sb subscriber', |
|
|
||
6 |
|
|
COUNT('sb book') |
AS 'sb has books' |
|
7 |
FROM |
|
'subscriptions' |
|
|
8 |
WHERE |
'sb is active' = |
'Y' |
|
|
9 |
GROUP |
BY 'sb_subscriber ; |
|
||
10 |
COMMIT ; |
|
|
||
|
|
|
|
|
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 460/545
Пример 43: управление уровнем изолированности транзакций
MySQL I |
Решение 6.2.1.b (проверочный код) |
| |
||
1 |
SELECT CONNECTION_ID(); |
|
||
2 |
SET autocommit = 0; |
|
||
3 |
START TRANSACTION; |
|
||
4 |
UPDATE 'subscriptions' |
|
||
5 |
SET |
'sb_is_active' = |
|
|
6 |
|
CASE |
|
|
|
|
WHEN |
'sb_is_active' = |
'Y' THEN 'N' |
8 |
|
WHEN |
'sb_is_active' = |
'N' THEN 'Y' |
9 |
|
END; |
|
|
10 |
SELECT SLEEP(10 ; |
|
||
11 |
COMMIT; |
|
|
|
|
|
|||
|
Код для MS SQL Server выглядит следующим образом. |
|||
|
|
|||
MS SQL I |
Решение 6.2.1.b (максимально быстрое выполнение, возможны некорректные данные) | |
1SELECT @@SPID;
2SET IMPLICIT TRANSACTIONS ON;
3SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
4BEGIN TRANSACTION;
5SELECT [sb subscriber],
6COUNT([sb book]) AS [sb has books]
7 FROM [subscriptions]
8WHERE [sb is active] = 'Y'
9GROUP BY [sb subscriber];
10COMMIT TRANSACTION;
MS SQL I |
Решение 6.2.1.b (максимально корректные данные, возможно долгое выполнение) |
і |
1SELECT @@SPID;
2SET IMPLICIT TRANSACTIONS ON;
3SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
4BEGIN TRANSACTION;
5SELECT [sb subscriber],
6COUNT([sb book] AS [sb has books]
7 |
FROM |
[subscriptions] |
8 |
WHERE |
[sb is active] = 'Y' |
9GROUP BY [sb subscriber];
10COMMIT TRANSACTION;
MS SQL I |
Решение 6.2.1.b (проверочный код) | |
1SELECT @@SPID;
2SET IMPLICIT_TRANSACTIONS ON;
3BEGIN TRANSACTION;
4UPDATE [subscriptions]
5 |
SET |
[sb is active] = |
|
|
6 |
|
CASE |
|
|
7 |
|
WHEN [sb is active] = 'Y |
THEN |
'N' |
8 |
|
WHEN [sb is active] = 'N |
THEN |
'Y' |
9END;
10WAITFOR DELAY '00:00:10';
11COMMIT TRANSACTION;
Код для Oracle выглядит следующим образом.
Oracle Решение 6.2.1.b (максимально быстрое выполнение, возможны некорректные данные)
1 COMMIT;
2SELECT SYS_CONTEXT('userenv','sessionid') FROM DUAL;
3SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
4SELECT "sb_subscriber",
5COUNT "sb_book") AS "sb_has_books"
6 |
FROM |
"subscriptions" |
|
7 |
WHERE |
"sb is active" = 'Y' |
|
|
GROUP BY |
"sb_subscriber"; |
|
9 |
COMMIT; |
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 461/545
Пример 43: управление уровнем изолированности транзакций
Oracle |
|
Решение 6.2.1.b (максимально корректные данные, возможно долгое выполнение) |
|
||||
1 |
COMMIT; |
|
|
|
|
||
2 |
SELECT SYS_CONTEXT('userenv','sessionid') FROM DUAL |
|
|||||
3 |
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; |
|
|||||
4 |
SELECT "sb_subscriber", |
|
|
|
|||
5 |
|
|
|
COUNT("sb_book") AS "sb_has_books" |
|
||
6 |
FROM |
"subscriptions" |
|
|
|
||
|
WHERE |
"sb_is_active" = 'Y' |
|
|
|
||
8 |
GROUP BY "sb_subscriber" |
|
|
|
|||
9 |
COMMIT; |
|
|
|
|
||
|
|
|
|
|
|
||
|
|
|
|
|
|||
Oracle |
|
Решение 6.2.1.b (проверочный код) |
|
|
|
||
1 |
COMMIT; |
|
|
|
|
||
2 |
SELECT SYS_CONTEXT('userenv','sessionid') FROM DUAL |
|
|||||
|
UPDATE |
"subscriptions" |
|
|
|
||
4 |
SET |
|
"sb_is_active" = |
|
|
|
|
5 |
|
|
|
CASE |
|
|
|
6 |
|
|
|
WHEN "sb_is_active" = |
'Y' THEN 'N' |
|
|
|
|
|
|
WHEN "sb_is_active" = |
|
'N' THEN 'Y' |
|
8 |
|
|
END; |
|
|
|
|
9 |
EXEC DBMS_LOCK.SLEEP(10 ; |
|
|
|
|||
10 |
COMMIT; |
|
|
|
|
||
|
|
|
|
|
|
|
|
Для всех трёх СУБД проверочный код необходимо выполнять в отдельной сессии (см. пояснения в решении{428} задачи 6.2.1.a{428}), при этом основной код надо выполнять до начала работы проверочного, во время его работы и после его завершения — это позволит наглядно увидеть, какие данные и в какой момент времени СУБД будет извлекать из базы данных.
Ещё один вариант поведения СУБД можно увидеть, заменив в проверочном коде последнюю команду с COMMIT на ROLLBACK.
Обратите особое внимание на отличие поведения Oracle от MySQL и MS SQL Server: даже в SERIALIZABLE-режиме запрос вернёт результаты без задержки.
На этом решение данной задачи завершено.
Задание 6.2.1.TSK.A: написать запросы, которые, будучи выполненными параллельно, обеспечивали бы следующий эффект:
•первый запрос должен считать количество выданных на руки и возвращённых в библиотеку книг и не зависеть от запросов на обновление таблицы subscriptions (не ждать их завершения);
•второй запрос должен инвертировать значения поля sb_is_active таблицы subscriptions с Y на N и наоборот и не зависеть от первого запроса (не ждать его завершения).
Задание 6.2.1.TSK.B: написать запросы, которые, будучи выполненными параллельно, обеспечивали бы следующий эффект:
•первый запрос должен считать количество выданных на руки и возвращённых в библиотеку книг;
•второй запрос должен инвертировать значения поля sb_is_active таблицы subscriptions с Y на N и наоборот для читателей с нечётными идентификаторами, после чего делать паузу в десять секунд и отменять
данное изменение (отменять транзакцию).
Исследовать поведение все трёх СУБД при выполнении первого запроса до, во время и после завершения выполнения второго запроса, повторив этот эксперимент для всех поддерживаемых конкретной СУБД уровней изолированности транзакций.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 462/545
Пример 44: взаимодействие конкурирующих транзакций
6.2.2.Пример 44: взаимодействие конкурирующих транзакций
ОЗадача 6.2.2.a{434}: продемонстрировать во всех трёх СУБД все аномалии конкурентного доступа для всех возможных комбинаций уровней изоли-
рованности транзакций.
О Задача 6.2.2.b{462}: продемонстрировать во всех трёх СУБД ситуацию гарантированного получения взаимной блокировки транзакций и реакцию СУБД
на такую ситуацию.
Ожидаемый результат 6.2.2.a.
Поскольку решение данной задачи и является ожидаемым результатом, см.
решение{434} 6.2.2.a.
Ожидаемый результат 6.2.2.b.
Поскольку решение данной задачи и является ожидаемым результатом, см.
решение{462} 6.2.2.b.
уЦ7
ЧР Решение 6.2.2.a{434}.
К аномалиям конкурентного доступа относятся:
•грязное чтение (dirty read) — чтение промежуточного состояния данных до того, как модифицирующая их транзакция будет подтверждена или отменена;
•потерянное обновление (lost update) — модификация одной и той же информации двумя и более транзакциями, при которой в силу вступают изменения, выполненные транзакцией, которая была подтверждена последней (а изменения, выполненные остальными транзакциями, теряются);
•неповторяющееся чтение (non-repeatable read) — получение различных результатов выполнения одного и того же запроса на чтение в рамках одной транзакции;
•фантомное чтение (phantom read) — временное появление (исчезновение) в наборе данных, с которым работает транзакция, тех или иных записей в силу их изменения другой транзакцией.
Для удобства навигации приведём таблицу, показывающую номера страниц, с которых начинается рассмотрение той или иной аномалии в каждой СУБД.
|
|
Потерянное |
Неповторяю- |
Фантомное |
|
Грязное чтение |
обновление |
щееся чтение |
чтение |
MySQL |
{435} |
{437} |
{440} |
{442} |
MS SQL Server |
{445} |
{447} |
{450} |
{452} |
Oracle |
{455} |
{457} |
{459} |
{461} |
Также отметим, что поскольку протоколы исследований будут выглядеть однотипно во всех СУБД, для экономии места мы ниже приведём их только для MySQL, причём в рамках исследования каждой аномалии конкурентного доступа для первой транзакции покажем только один уровень изолированности, а для второй — все поддерживаемые данной СУБД уровни изолированности.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 463/545
Пример 44: взаимодействие конкурирующих транзакций
Традиционно начинаем с MySQL. Данная СУБД поддерживает четыре уровня изолированности транзакций, комбинации которых мы и рассмотрим:
•READ UNCOMMITTED;
•READ COMMITTED;
•REPEATABLE READ;
•SERIALIZABLE.
Для выполнения эксперимента используем командный файл:
start cmd.exe /с "mysql -иПОЛЬЗЬВАТЕЛЬ -рПАРОЛЬ БАЗА_ДАННЫХ < a.sql & pause" start cmd.exe /c "mysql иПОЛЬЗЬВАТЕЛЬ ^ПАРОЛЬ БАЗА ДАННЫХ < b.sql & pause"
Г рязное чтение в MySQL может быть исследовано выполнением в двух отдельных сессиях следующих блоков кода:
MySQL |
Решение 6.2.2.a (код для исследования аномалии грязного чтения) |
|
1 |
-- Транзакция A: |
-- Транзакция B: |
||
2 |
SELECT CONCAT('Tr A ID = ', |
SELECT CONCAT('Tr B ID = ', |
||
3 |
|
CONNECTION_ID()); |
|
CONNECTION_ID()); |
4 |
SET autocommit = 0; |
SET autocommit = 0; |
||
5 |
SET SESSION TRANSACTION |
SET SESSION TRANSACTION |
||
|
ISOLATION LEVEL {УРОВЕНЬ}; |
ISOLATION LEVEL {УРОВЕНЬ}; |
||
|
|
|
||
|
START TRANSACTION; |
START TRANSACTION; |
||
8 |
SELECT CONCAT('Tr A START: ', |
SELECT CONCAT('Tr B START: ', |
||
9 |
|
CURTIME(), ' in '); |
|
CURTIME(), ' in '); |
10 |
SELECT |
'VARIABLE_VALUE' |
SELECT 'VARIABLE_VALUE' |
|
11 |
FROM |
'information_schema' |
FROM |
'information_schema' |
12 |
|
'session_variables' |
|
'session_variables' |
13 |
WHERE |
'VARIABLE_NAME' = |
WHERE |
'VARIABLE_NAME' = |
14 |
|
'tx isolation'; |
|
'tx isolation'; |
15 |
|
|
SELECT CONCAT('Tr B SELECT 1: ', |
|
16 |
|
|
|
CURTIME()); |
17 |
SELECT SLEEP(5); |
SELECT 'sb_is_active' |
||
18 |
|
|
FROM |
'subscriptions' |
19 |
|
|
WHERE |
'sb id' = 2; |
|
SELECT CONCAT('Tr A UPDATE: ', |
|
|
|
11 |
|
CURTIME()); |
|
|
12 |
UPDATE |
'subscriptions' |
|
|
13 |
SET |
'sb_is_active' = |
|
|
14 |
CASE |
|
SELECT SLEEP (10); |
|
|
WHEN |
'sb_is_active' = 'Y' THEN 'N' |
|
|
16 |
WHEN |
'sb_is_active' = 'N' THEN 'Y' |
|
|
17 |
END |
|
|
|
|
WHERE |
'sb id' = 2; |
|
|
19 |
|
|
SELECT CONCAT('Tr B SELECT 2: ', |
|
20 |
|
|
|
CURTIME()); |
21 |
SELECT SLEEP(20 ; |
SELECT 'sb_is_active' |
||
22 |
|
|
FROM |
'subscriptions' |
23 |
|
|
WHERE |
'sb id' = 2; |
24 |
|
|
SELECT CONCAT('Tr B COMMIT: ', |
|
25 |
|
|
|
CURTIME()); |
26 |
|
|
COMMIT; |
|
|
|
|
|
|
|
SELECT CONCAT('Tr A ROLLBACK: ', |
|
|
|
28 |
|
CURTIME()); |
|
|
29 |
ROLLBACK; |
|
|
Приведём пример журнала выполнения этого кода для ситуации, когда транзакция A выполняется на уровне изолированности READ UNCOMMITTED и конкурирует с транзакцией B, последовательно выполняемой во всех поддерживаемых MySQL уровнях изолированности.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 464/545
Пример 44: взаимодействие конкурирующих транзакций
|
A: READ UNCOMMITTED |
B: READ UNCOMMITTED |
Tr |
A ID = 13 |
Tr B ID = 14 |
Tr |
A START: 17:21:01 in READ-UNCOMMITTED |
Tr B START: 17:21:01 in READ-UNCOMMITTED |
Tr |
A UPDATE: 17:21:06 |
Tr B SELECT 1: 17:21:01 |
Tr |
A ROLLBACK: 17:21:26 |
sb is active = Y |
|
|
Tr B SELECT 2: 17:21:11 |
|
|
sb_is_active = N |
|
|
Tr B COMMIT: 17:21:11 |
|
A: READ UNCOMMITTED |
B: READ COMMITTED |
Tr |
A ID = 15 |
Tr B ID = 16 |
Tr |
A START: 17:38:06 in READ-UNCOMMITTED |
Tr B START: 17:38:06 in READ-COMMITTED |
Tr |
A UPDATE: 17:38:12 |
Tr B SELECT 1: 17:38:06 |
Tr |
A ROLLBACK: 17:38:32 |
sb is active = Y |
|
|
Tr B SELECT 2: 17:38:16 |
|
|
sb_is_active = Y |
|
|
Tr B COMMIT: 17:38:16 |
|
|
|
|
A: READ UNCOMMITTED |
B: REPEATABLE READ |
Tr |
A ID = 18 |
Tr B ID = 17 |
Tr |
A START: 17:42:37 in READ-UNCOMMITTED |
Tr B START: 17:42:37 in REPEATABLE-READ |
Tr |
A UPDATE: 17:42:42 |
Tr B SELECT 1: 17:42:37 |
Tr |
A ROLLBACK: 17:43:02 |
sb is active = Y |
|
|
Tr B SELECT 2: 17:42:47 |
|
|
sb_is_active = Y |
|
|
Tr B COMMIT: 17:42:47 |
|
|
|
|
|
A: READ UNCOMMITTED |
|
|
|
|
B: SERIALIZABLE |
||
Tr |
A ID = 20 |
|
|
|
Tr B ID = |
19 |
|
||
Tr |
A START: 17:48:19 in READ-UNCOMMITTED |
|
Tr B START: 17:48:19 in SERIALIZABLE |
||||||
Tr |
A UPDATE: 17:48:24 |
|
|
|
Tr B SELECT 1: 17:48:19 |
|
|||
Tr |
A ROLLBACK: 17:48:49 |
|
|
sb is active = Y |
|
||||
|
|
|
|
|
|
Tr B SELECT 2: 17:48:29 |
|
||
|
|
|
|
|
|
sb_is_active = Y |
|
||
|
|
|
|
|
|
Tr B COMMIT: 17:48:29 |
|
||
|
|
Итоговые результаты взаимодействия транзакций таковы. |
|
||||||
|
|
|
|
|
|
|
|||
|
|
|
|
Уровень изолированности транзакции B |
|||||
|
|
|
READ |
READ COMMITTED |
|
REPEATABLE |
SERIALIZABLE |
||
|
|
|
UNCOMMITTED |
|
READ |
||||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Транзакция B оба раза |
|
|
|
Транзакция B |
Транзакция B оба |
|
Транзакция B оба |
читает исходное |
||
|
|
READ |
успевает прочитать |
|
раза читает |
|
раза читает |
(корректное) значение, |
|
|
|
UNCOMMITTED |
незафикси- |
исходное (кор- |
|
исходное (кор- |
UPDATE в транзакции A |
||
|
|
|
рованное значение |
ректное) значение |
|
ректное) значение |
ждёт завершения |
||
|
A |
|
|
|
|
|
|
|
транзакции B |
|
транзакции |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Транзакция B оба раза |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Транзакция B |
Транзакция B оба |
|
Транзакция B оба |
читает исходное |
||
|
|
READ |
успевает прочитать |
|
раза читает |
|
раза читает |
(корректное) значение, |
|
|
изолированности |
COMMITTED |
незафикси- |
исходное (кор- |
|
исходное (кор- |
UPDATE в транзакции A |
||
|
READ |
незафикси- |
исходное (кор- |
|
исходное (кор- |
UPDATE в транзакции A |
|||
|
|
|
рованное значение |
ректное) значение |
|
ректное) значение |
ждёт завершения |
||
|
|
|
|
|
|
|
|
|
транзакции B |
|
|
|
|
|
|
|
|
|
Транзакция B оба раза |
|
|
|
Транзакция B |
Транзакция B оба |
|
Транзакция B оба |
читает исходное |
||
|
|
REPEATABLE |
успевает прочитать |
|
раза читает |
|
раза читает |
(корректное) значение, |
|
|
Уровень |
|
рованное значение |
ректное) значение |
|
ректное) значение |
ждёт завершения |
||
|
|
|
|
|
|
|
|
Транзакция B оба раза |
|
|
|
|
|
|
|
|
|
|
транзакции B |
|
|
|
Транзакция B |
Транзакция B оба |
|
Транзакция B оба |
читает исходное |
||
|
|
SERIALIZABLE |
успевает прочитать |
|
раза читает |
|
раза читает |
(корректное) значение, |
|
|
|
незафикси- |
исходное (кор- |
|
исходное (кор- |
UPDATE в транзакции A |
|||
|
|
|
|
||||||
|
|
|
рованное значение |
ректное) значение |
|
ректное) значение |
ждёт завершения |
||
|
|
|
|
|
|
|
|
|
транзакции B |
|
|
|
|
|
|
|
|
|
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 465/545
Пример 44: взаимодействие конкурирующих транзакций
Потерянное обновление MySQL может быть исследовано выполнением в двух отдельных сессиях следующих блоков кода:
MySQL I Решение 6.2.2.a (код для исследования аномалии потерянного обновления) |
1 |
-- Транзакция A: |
|
|
-- Транзакция B: |
|||
2 |
SELECT CONCAT('Tr A ID = |
', |
|
SELECT CONCAT('Tr B ID = ', |
|||
3 |
|
CONNECTION_ID()); |
|
|
CONNECTION_ID()); |
||
4 |
SET autocommit = 0; |
|
|
SET autocommit = 0; |
|||
5 |
SET SESSION TRANSACTION |
|
|
SET SESSION TRANSACTION |
|||
|
ISOLATION LEVEL {УРОВЕНЬ}; |
|
ISOLATION LEVEL {УРОВЕНЬ}; |
||||
|
START TRANSACTION; |
|
|
START TRANSACTION; |
|||
8 |
SELECT CONCAT('Tr A START: ', |
|
SELECT CONCAT('Tr B START: ', |
||||
9 |
|
CURTIME(), ' in '); |
|
CURTIME(), ' in '); |
|||
10 |
SELECT |
'VARIABLE_VALUE' |
|
|
SELECT 'VARIABLE_VALUE' |
||
11 |
FROM |
'information_schema' |
|
FROM |
'information_schema' |
||
12 |
|
'session_variables' |
|
|
'session_variables' |
||
13 |
WHERE |
'VARIABLE_NAME' = |
|
|
WHERE |
'VARIABLE_NAME' = |
|
14 |
|
'tx isolation'; |
|
|
|
'tx isolation'; |
|
|
SELECT CONCAT('Tr A, SELECT: ', |
|
|
|
|
||
16 |
|
CURTIME () ) ; |
|
|
|
|
|
17 |
SELECT |
'sb_is_active' |
|
|
SELECT SLEEP(5 ; |
||
18 |
FROM |
'subscriptions' |
|
|
|
|
|
|
WHERE |
'sb id' = 2; |
|
|
|
|
|
20 |
|
|
|
|
SELECT CONCAT('Tr B, SELECT: ', |
||
21 |
|
|
|
|
|
CURTIME()); |
|
22 |
SELECT SLEEP(10 ; |
|
|
SELECT 'sb_is_active' |
|||
23 |
|
|
|
|
FROM |
'subscriptions' |
|
24 |
|
|
|
|
WHERE |
'sb id' = 2; |
|
|
|
|
|
|
|
||
|
SELECT CONCAT('Tr A UPDATE: ', |
|
|
|
|
||
26 |
|
CURTIME () ) ; |
|
|
|
|
|
27 |
UPDATE |
'subscriptions' |
|
|
|
|
|
28 |
SET |
'sb_is_active' |
= |
'Y' |
SELECT SLEEPi10>; |
||
29 |
WHERE |
'sb_id' = 2; |
|
|
|||
|
|
|
|
|
|||
30 |
SELECT CONCAT('Tr A COMMIT: ', |
|
|
|
|
||
31 |
|
CURTIME()); |
|
|
|
|
|
|
COMMIT; |
|
|
|
|
|
|
33 |
|
|
|
|
SELECT CONCAT('Tr B UPDATE: ', |
||
34 |
|
|
|
|
|
CURTIME()); |
|
35 |
|
|
|
|
UPDATE 'subscriptions' |
||
36 |
SELECT SLEEP(10 ; |
|
|
SET |
'sb_is_active' = 'N' |
||
37 |
|
|
|
|
WHERE |
'sb_id' = 2; |
|
38 |
|
|
|
|
SELECT CONCAT('Tr B COMMIT: ' , |
||
39 |
|
|
|
|
|
CURTIME()); |
|
40 |
|
|
|
|
COMMIT; |
|
|
|
|
|
|
||||
|
SELECT CONCAT('After A, SELECT: ', |
SELECT CONCAT('After B, SELECT: ', |
|
||||
42 |
|
CURTIME()); |
|
|
|
CURTIME()); |
|
43 |
SELECT |
'sb_is_active' |
|
|
SELECT 'sb_is_active' |
|
|
44 |
FROM |
'subscriptions' |
|
|
FROM |
'subscriptions' |
|
45 |
WHERE |
'sb id' = 2; |
|
|
WHERE |
'sb id' = 2; |
|
Приведём пример журнала выполнения этого кода для ситуации, когда транзакция A выполняется на уровне изолированности READ COMMITTED и конкурирует с
транзакцией B, последовательно выполняемой во всех поддерживаемых MySQL уровнях изолированности.
A: READ COMMITTED |
B: READ UNCOMMITTED |
Tr A ID = 77 |
Tr B ID = 76 |
Tr A START:19:12:19 in READ-COMMITTED |
Tr B START: 19:12:19 in READ-UNCOMMITTED |
Tr A, SELECT: 19:12:19 |
Tr B, SELECT: 19:12:24 |
sb is active = N |
sb is active = N |
Tr A UPDATE: 19:12:29 |
Tr B UPDATE: 19:12:34 |
Tr A COMMIT: 19:12:29 |
Tr B COMMIT: 19:12:34 |
After A, SELECT: 19:12:39 |
After B, SELECT: 19:12:34 |
sb is active = N |
sb_is_active = N |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 466/545
Пример 44: взаимодействие конкурирующих транзакций
A: READ COMMITTED |
|
B: READ COMMITTED |
Tr A ID = 80 |
|
Tr B ID = 79 |
Tr A START:19:14:43 in READ-COMMITTED |
Tr B START: 19:14:43 in READ-COMMITTED |
|
Tr A, SELECT: 19:14:43 |
|
Tr B, SELECT: 19:14:48 |
sb is active = N |
|
sb is active = N |
' UPDATE: 19:14:53 |
|
B UPDATE: 19:14:58 |
Tr A COMMIT: 19:14:53 |
|
Tr B COMMIT: 19:14:58 |
After A, SELECT: 19:15:03 sb |
is active |
After B, SELECT: 19:14:58 |
= N |
|
sb_is_active = N |
A: READ COMMITTED |
B: REPEATABLE READ |
|
Tr A ID = 83 |
Tr B ID = |
82 |
Tr ASTART: 19:17:00 in READ-COMMITTED |
Tr BSTART: 19:17:00 in REPEATABLE-READ |
|
Tr A, SELECT:19:17:00 |
Tr B, SELECT: 19:17:05 |
|
sb is active = N |
sb is active = |
N |
Tr A UPDATE: 19:17:10 |
Tr B UPDATE: 19:17:15 |
|
Tr A COMMIT: 19:17:10 |
Tr B COMMIT: 19:17:15 |
|
After A, SELECT: 19:17:20 |
After B, SELECT: 19:17:15 |
|
sb is active = N |
sb is active = N |
|
|
|
|
|
A: READ COMMITTED |
|
|
|
B: SERIALIZABLE |
||||
Tr A ID = 86 |
|
|
|
Tr B ID = |
85 |
|
|
||
Tr ASTART: 19:19:07 |
in READ-COMMITTED |
|
Tr BSTART: 19:19:06 in SERIALIZABLE |
||||||
Tr A, SELECT:19:19:07 |
|
|
|
Tr B, SELECT: 19:19:11 |
|
||||
sb is active = N |
|
|
|
sb is active = N |
|
||||
Tr A UPDATE: 19:19:17 |
|
|
|
Tr B UPDATE: 19:19:21 |
|
||||
Tr A COMMIT: 19:19:17 |
|
|
|
Tr B COMMIT: 19:19:21 |
|
||||
After A, SELECT: 19:19:27 |
|
After B, SELECT: 19:19:21 |
|
||||||
sb is active = N |
|
|
|
sb is active = N |
|
||||
|
Итоговые результаты взаимодействия транзакций таковы. |
|
|||||||
|
|
|
|
|
|
|
|||
|
|
|
|
Уровень изолированности транзакции B |
|||||
|
|
READ |
|
|
|
|
REPEATABLE |
|
SERIALIZABLE |
|
|
UNCOMMITTED |
READ COMMITTED |
|
READ |
|
|||
|
|
|
|
|
|||||
A |
|
Обновление |
|
Обновление |
|
Обновление |
|
|
|
транзакции |
READ |
|
|
|
Обновление транзакции |
||||
транзакции A |
|
транзакции A |
|
транзакции A |
|
||||
UNCOMMITTED |
|
|
|
A утеряно |
|||||
|
|
|
|
||||||
|
утеряно |
|
утеряно |
|
утеряно |
|
|||
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
изолированности |
READ |
Обновление |
|
Обновление |
|
Обновление |
|
Обновление транзакции |
|
утеряно |
|
утеряно |
|
утеряно |
|
||||
|
COMMITTED |
транзакции A |
|
транзакции A |
|
транзакции A |
|
A утеряно |
|
|
утеряно |
|
утеряно |
|
утеряно |
|
|||
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
REPEATABLE |
Обновление |
|
Обновление |
|
Обновление |
|
Обновление транзакции |
|
|
транзакции A |
|
транзакции A |
|
транзакции A |
|
|||
|
READ |
|
|
|
A утеряно |
||||
|
|
|
|
|
|
|
|
||
Уровень |
|
|
|
|
|
|
|
|
|
|
Обновление |
|
Обновление |
|
Обновление |
|
Возможна взаимная |
||
|
|
|
|
|
|||||
|
SERIALIZABLE |
транзакции A |
|
транзакции A |
|
транзакции A |
|
блокировка с отменой |
|
|
|
утеряно |
|
утеряно |
|
утеряно |
|
транзакции B |
|
|
|
|
|
|
|
|
|
|
|
Если в данном эксперименте убрать чтение информации перед её обновлением (строки 15-19 для транзакции A, и строки 20-24 для транзакции B), то при любой комбинации уровней изолированности результат будет одним и тем же: изменения, выполненные транзакцией A, будут утеряны.
Чтобы получить другой вариант поведения СУБД, необходимо явно блокиро-
вать читаемые записи (SELECT ... LOCK IN SHARE MODE или SELECT ... FOR UPDATE)36 в первой операции чтения. В данном случае это не было сделано, чтобы
продемонстрировать наиболее типичное поведение MySQL. Но если добавить указанные блокировки, поведение MySQL изменится и примет следующий вид.
36 http://dev.mysql.com/doc/refman/5.6/en/innodb-locking-reads.html
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 467/545
Пример 44: взаимодействие конкурирующих транзакций
Итоговые результаты взаимодействия транзакций при использовании LOCK IN SHARE MODE для первой операции чтения. Важно отметить, что в некоторых случаях
взаимная блокировка нарушает работу обеих транзакций, но в большинстве случаев СУБД отменяет транзакцию B, позволяя транзакции A успешно выполниться.
|
|
|
Уровень изолированности транзакции B |
|
||
|
|
READ |
|
REPEATABLE |
SERIALIZABLE |
|
|
|
UNCOMMITTED |
READ COMMITTED |
READ |
||
|
|
|
||||
A |
|
|
|
|
|
|
транзакции |
READ |
Взаимная блоки- |
Взаимная блоки- |
Взаимная блоки- |
Взаимная блоки- |
|
UNCOMMITTED |
ровка транзакций |
ровка транзакций |
ровка транзакций |
ровка транзакций |
||
|
||||||
|
|
|
|
|
|
|
изолированности |
READ |
Взаимная блоки- |
Взаимная блоки- |
Взаимная блоки- |
Взаимная блоки- |
|
COMMITTED |
ровка транзакций |
ровка транзакций |
ровка транзакций |
ровка транзакций |
||
|
||||||
|
|
|
|
|
|
|
|
REPEATABLE |
Взаимная блоки- |
Взаимная блоки- |
Взаимная блоки- |
Взаимная блоки- |
|
|
READ |
ровка транзакций |
ровка транзакций |
ровка транзакций |
ровка транзакций |
|
Уровень |
|
|
|
|
|
|
SERIALIZABLE |
Взаимная блоки- |
Взаимная блоки- |
Взаимная блоки- |
Взаимная блоки- |
||
|
||||||
|
ровка транзакций |
ровка транзакций |
ровка транзакций |
ровка транзакций |
||
|
|
|||||
|
|
|
|
|
|
Итоговые результаты взаимодействия транзакций при использовании FOR UPDATE для первой операции чтения.
|
|
|
Уровень изолированности транзакции B |
|
||
|
|
READ |
READ COMMITTED |
REPEATABLE |
SERIALIZABLE |
|
|
|
UNCOMMITTED |
READ |
|||
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
Обновление тран- |
Обновление тран- |
Обновление тран- |
Обновление тран- |
|
A |
READ |
закции A утеряно, |
закции A утеряно, |
закции A утеряно, |
закции A утеряно, |
|
транзакции |
||||||
UNCOMMITTED |
транзакция B ждёт |
транзакция B ждёт |
транзакция B ждёт |
транзакция B ждёт |
||
|
||||||
|
|
завершения A |
завершения A |
завершения A |
завершения A |
|
|
|
|
|
|
|
|
|
|
Обновление тран- |
Обновление тран- |
Обновление тран- |
Обновление тран- |
|
изолированности |
READ |
закции A утеряно, |
закции A утеряно, |
закции A утеряно, |
закции A утеряно, |
|
COMMITTED |
завершения A |
завершения A |
завершения A |
завершения A |
||
|
транзакция B ждёт |
транзакция B ждёт |
транзакция B ждёт |
транзакция B ждёт |
||
|
|
завершения A |
завершения A |
завершения A |
завершения A |
|
|
|
Обновление тран- |
Обновление тран- |
Обновление тран- |
Обновление тран- |
|
|
REPEATABLE |
закции A утеряно, |
закции A утеряно, |
закции A утеряно, |
закции A утеряно, |
|
|
READ |
транзакция B ждёт |
транзакция B ждёт |
транзакция B ждёт |
транзакция B ждёт |
|
Уровень |
|
|
|
|
|
|
|
Обновление тран- |
Обновление тран- |
Обновление тран- |
Обновление тран- |
||
|
|
|||||
|
SERIALIZABLE |
закции A утеряно, |
закции A утеряно, |
закции A утеряно, |
закции A утеряно, |
|
|
транзакция B ждёт |
транзакция B ждёт |
транзакция B ждёт |
транзакция B ждёт |
||
|
|
|||||
|
|
завершения A |
завершения A |
завершения A |
завершения A |
|
|
|
|
|
|
|
Очевидно, что использованием различных комбинаций способов выполнения (или вовсе невыполнение) первой операции чтения в начале каждой транзакции можно получить ещё больше вариантов поведения СУБД.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 468/545
Пример 44: взаимодействие конкурирующих транзакций
Неповторяющееся чтение в MySQL может быть исследовано выполнением в двух отдельных сессиях следующих блоков кода:
MySQL I Решение 6.2.2.a (код для исследования аномалии неповторяющегося чтения) |
1 |
-- Транзакция A: |
|
-- Транзакция B: |
||
2 |
SELECT CONCAT('Tr A ID = |
', |
SELECT CONCAT('Tr B ID = ', |
||
3 |
|
CONNECTION ID()) ; |
|
CONNECTION ID()); |
|
4 |
SET autocommit = 0; |
|
SET autocommit = 0; |
||
5 |
SET SESSION TRANSACTION |
|
SET SESSION TRANSACTION |
||
|
ISOLATION LEVEL {УРОВЕНЬ}; |
ISOLATION LEVEL {УРОВЕНЬ}; |
|||
|
|
|
|
|
|
|
START TRANSACTION; |
|
START TRANSACTION; |
||
7 |
SELECT CONCAT('Tr A START: ', |
SELECT CONCAT('Tr B START: ', |
|||
8 |
|
CURTIME(), ' in '); |
|
CURTIME(), ' in '); |
|
9 |
SELECT 'VARIABLE VALUE' |
|
SELECT 'VARIABLE VALUE' |
||
10 |
FROM |
'information schema' |
FROM |
'information schema' |
|
11 |
|
'session variables' |
|
'session variables' |
|
12 |
WHERE |
'VARIABLE NAME' = |
|
WHERE |
'VARIABLE NAME' = |
13 |
|
'tx isolation'; |
|
|
'tx isolation'; |
14 |
|
|
|
SELECT CONCAT('Tr A SELECT-1: ', |
|
15 |
|
|
|
|
CURTIME()); |
16 |
SELECT SLEEP(5); |
|
|
|
|
17 |
|
|
|
SELECT 'sb is active' |
|
18 |
|
|
|
FROM |
'subscriptions' |
19 |
|
|
|
WHERE |
'sb id' = 2; |
|
SELECT CONCAT('Tr A UPDATE: ', |
|
|
||
21 |
|
CURTIME()); |
|
|
|
22 |
UPDATE 'subscriptions' |
|
|
|
|
23 |
SET |
'sb is active' = |
|
|
|
24 |
CASE |
|
|
SELECT SLEEPi10>; |
|
25 |
WHEN 'sb is active' = |
'Y' THEN 'N' |
|
|
|
26 |
WHEN 'sb is active' = |
'N' THEN 'Y' |
|
|
|
|
|
|
|
|
|
27 |
END |
|
|
|
|
28 |
WHERE |
'sb id' = 2; |
|
|
|
29 |
SELECT CONCAT('Tr A COMMIT: ', |
|
|
||
30 |
|
CURTIME()); |
|
|
|
|
COMMIT; |
|
|
|
|
|
|
|
|
|
|
32 |
|
|
|
SELECT CONCAT('Tr A SELECT-2: ', |
|
33 |
|
|
|
|
CURTIME()); |
34 |
|
|
|
|
|
35 |
|
|
|
SELECT 'sb is active' |
|
36 |
|
|
|
FROM |
'subscriptions' |
37 |
|
|
|
WHERE |
'sb id' = 2; |
38 |
|
|
|
SELECT CONCAT('Tr B COMMIT: ', |
|
39 |
|
|
|
|
CURTIME()); |
40 |
|
|
|
COMMIT; |
|
|
|
|
|
|
|
Приведём пример журнала выполнения этого кода для ситуации, когда транзакция A выполняется на уровне изолированности REPEATABLE READ и конкурирует
с транзакцией B, последовательно выполняемой во всех поддерживаемых MySQL уровнях изолированности.
|
A: REPEATABLE READ |
B: READ UNCOMMITTED |
Tr |
A ID = 151 |
Tr B ID = 152 |
Tr |
A START:20:24:12 in REPEATABLE-READ |
Tr B START: 20:24:12 in READ-UNCOMMITTED |
Tr |
A UPDATE:20:24:17 |
Tr B SELECT-1: 20:24:12 |
Tr |
A COMMIT:20:24:17 |
sb_is_active = N |
|
|
Tr B SELECT-2: 20:24:22 |
|
|
sb_is_active = Y |
|
|
Tr B COMMIT: 20:24:22 |
|
|
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 469/545