Материал: Using_MySql,_MS_SQL_Server_and_Oracle

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Пример 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

Источник: https://studfile.net/preview/16420333/