- •Практическая работа. Бизнес-транзакции и транзакции sql Server
- •Управление изоляцией транзакций
- •Мониторинг блокировок
- •Уровень изоляции транзакции
- •Используем только чтение зафиксированных данных
- •Применяем уровень изоляции read commited
- •Применяем уровень изоляции read commited snapshot
- •Как добиться согласованных повторяющихся операций чтения
- •Применяем уровень изоляции snapshot
- •Как предотвратить параллельные изменения данных
- •Применяем уровень изоляции repeatable read
- •Применяем уровень изоляции serializable
- •Борьба с блокированиями
- •Выполняем мониторинг блокирований при помощи динамических административных представлений
- •Борьба с взаимоблокировками
- •Разыгрываем простой сценарий взаимоблокировки
- •5. Закройте все окна запросов.
Применяем уровень изоляции snapshot
Запустите SQL Server Management Studio и откройте окно New Query (Новый запрос).
Уровень изоляции SNAPSHOT (мгновенный снимок) необходимо активировать для базы данных однократно. После активации этот уровень может использоваться при необходимости любым соединением. Чтобы разрешить уровень изоляции SNAPSHOT в базе данных, выполните следующую инструкцию.
USE master;
ALTER DATABASE Ваша_База_Данных
SET ALLOW_SNAPSHOT_ISOLATION ON;
3. Теперь представьте себе, что нужно создать несколько отчетов по таблице Поставки. Необходимым условием является согласование операций чтения. Выполните следующие инструкции, чтобы активировать изоляцию SNAPSHOT для транзакций и запустите транзакцию, которая возвращает сумму линейных итогов для одного Проекта. Запомните значение Общее_количество.
USE Ваша_База_Данных;
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
BEGIN TRAN
SELECT SUM(Количество) as Общее_количество
FROM Поставки WHERE Код_Проекта = ‘J4’
4. Откройте еще одно окно запроса и обновите таблицу SalesOrderDetail,чтобы изменить базовые данные для запроса в окне запроса QueryWindow 1. (Замените/добавьте количество деталей P2, поставляемых поставщиком S3 для проекта J4 на 555)
5. Закройте окно запроса Query Window 2, перейдите обратно в окно Query Window 1 и повторите инструкцию SELECT.
Как видите, результат тот же, что был до этого, поскольку изоляция SNAPSHOT игнорирует изменения данных в процессе выполнения транзакции. Она всегда предоставляет последние зафиксированные с начала транзакции значения.
6. Зафиксируйте все транзакции и повторите чтение, выполнив следующий код. Вы увидите, что этот результат будет другим, потому что транзакция завершилась.
COMMIT TRAN
SELECT SUM(Количество) as Общее_количество
FROM Поставки WHERE Код_Проекта = ‘J4’
7. Выполните следующий код, чтобы отключить изоляцию SNAPSHOT в базе данных
ALTER DATABASE Ваша_База_данных
SET ALLOW_SNAPSHOT_ISOLATION OFF;
Как предотвратить параллельные изменения данных
Как мы наблюдали в предыдущих примерах, изоляция SNAPSHOT не блокирует данные в процессе чтения, но обеспечивает согласованное представление на протяжении всей транзакции. Но в некоторых ситуациях необходимо заблокировать данные на протяжении всей транзакции, чтобы избежать обновления данных другими транзакциями. Предположим, что нужно выписать счет за заказ. Сначала нужно извлечь данные и проверить их, а затем сгенерировать счет на их основе. В такой транзакции необходимо заблокировать данные с самого начала, чтобы предотвратить изменения, которые могут сделать другие транзакции. В этом случае ни уровень SNAPSHOT, ни уровень READ COMMITED не будут подходящими вариантами. В такой ситуации можно использовать уровень изоляции REPEATABLE READ (повторяющиеся чтения). Этот уровень аналогичен уровню READ COMMITED без SNAPSHOT, но удерживает разделяемые блокировки до окончания транзакции. Следовательно, он предотвратит изменения данных.
Применяем уровень изоляции repeatable read
Запустите SQL Server Management Studio и откройте окно NewQuery (Новый запрос).
Допустим, что нам нужно обработать поставку деталей для проекта J4. Сначала нужно выполнить выборку данных. Чтобы не допустить изменения данных другими транзакциями в процессе чтения, используйте уровень изоляции REPEATABLE READ. Выполните следующий код
USE Ваша_База_Данных;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRAN
SELECT Количество
FROM Поставки WHERE Код_Проекта = ‘J4’ AND Код_Детали=’P2’ AND Код_Поставщика=‘S3’
3. Откройте еще одно окно запроса и попробуйте обновить таблицу Поставки, чтобы изменить базовые данные запроса в окнеQuery Window 1; замените количество деталей P2, поставляемых поставщиком S3 для проекта J4 на 555
Запрос ожидает. В отличие от уровня изоляции SNAPSHOT, невозможно обновить данные, поскольку разделяемые блокировки удерживаются для предотвращения изменения данных другими транзакциями. Эти блокировки можно увидеть через административное представление sys.dm_tran_locks, которое мы использовали ранее.
4. Нажмите кнопку Cancel Executing Query (Отменить выполнение запроса) на панели инструментов (она показана на рис. вверху следующей страницы), чтобы отменить запрос в окне запроса Query Window2; вместо этого запроса выполните инструкцию INSERT, чтобы добавить в заказ новую строку:
INSERT INTO Поставки
(Код_Поставщика, Код_Детали, Код_Проекта) VALUES(‘S3’,’P2’,’J4’, 888)
5. Обратите внимание на то, что эта инструкция успешно выполняется, хотя используется уровень изоляции REPEAT ABLE READ. Так происходит потому, что REPETABLE READ блокирует данные для предотвращения изменения данных, а инструкция INSERT вставляет новые данные в базу данных, а это не запрещено. Поскольку новая строка попадает в диапазон инструкции SELECT транзакции из окна Window1, она будет считана при следующем извлечении транзакцией этих данных. Такие строки называются фантомными чтениями.
6. Повторите инструкцию SELECT и зафиксируйте (COMMIT) транзакцию, как показано ниже.
SELECT Количество
FROM Поставки WHERE Код_Проекта = ‘J4’ AND Код_Детали=’P2’ AND Код_Поставщика=‘S3’
COMMIT TRAN
Обратите внимание, что новая строка была считана инструкцией SELECT, потому что она попала в диапазон инструкции. Уровень REPEATABLE READ предотвращает изменение существующих данных, но не предотвращает вставки новых данных в диапазон инструкции SELECT.
7. Закройте окно среды SQL Server Management Studio.
Блокирование и взаимоблокировки
Чтобы гарантировать, что транзакция не будет читать фантомные данные, можно заблокировать данные, задав блокировку диапазона исследуемых данных. Однако это может вызвать проблему взаимоблокировок.
Блокировка последовательных блоков связанных данных
Чтобы предотвратить фантомные чтения, можно использовать уровень изоляции SERIALIZABLE (упорядоченное чтение). Этот уровень является более строгим, чем уровень REPEATABLE READ; он блокирует не только данные, которые считываются в процессе транзакции, но и диапазон, который читает транзакция. Это достигается использованием особых видов блокировок, которые называются блокировками диапазона ключей, в индексах. Блокировки диапазона ключей блокируют диапазоны, заданные в предложении WHERE инструкции SELECT. Эти блокировки могут использоваться только в том случае, если существует соответствующий индекс. Если индекс не существует, то SQL Server должен использовать блокировку на уровне таблицы, чтобы предотвратить вставки данных в этот диапазон. Следовательно, уровень изоляции SERIALIZABLE должен использоваться только в том случае, если он абсолютно необходим.
