Опубликован: 11.12.2006 | Доступ: свободный | Студентов: 5820 / 381 | Оценка: 4.42 / 3.86 | Длительность: 57:15:00
Лекция 19:

Транзакции и блокировка транзакций

Блокирование и взаимоблокировки

Блокирование (blocking) и взаимоблокировки (deadlock) – это две дополнительные проблемы, которые могут возникать при одновременно выполняемых транзакциях. Они могут приводить к серьезным проблемам системы, а также могут замедлять и даже останавливать работу. Эти проблемы могут разрешаться в приложении, или SQL Server постарается сделать все возможное для их разрешения; они будут описаны здесь только для того, чтобы вы представляли их себе и понимали используемые концепции. Обход и разрешение проблем блокирования и взаимоблокировки являются обязанностью программиста.

Блокирование возникает в том случае, когда одна транзакция владеет блокировкой по какому-либо ресурсу, а второй транзакции требуется конфликтный тип блокировки по этому ресурсу. Вторая транзакция должна ждать, пока первая транзакция освободит свою блокировку; иными словами, она блокирована первой транзакцией. Проблема блокирования обычно возникает, когда какая-либо транзакция захватывает блокировку на длительный период времени, что приводит к цепочке блокированных транзакций, ожидающих окончания других транзакций, чтобы получить необходимые им блокировки; это состояние называют цепным блокированием. На рис. 19.1 показан пример цепного блокирования.

Взаимоблокировка отличается от блокированной транзакции в том, что взаимоблокировка возникает в случае двух блокированных транзакций, ожидающих друг друга. Например, предположим, что одна транзакция владеет монопольной блокировкой по Таблице 1, а вторая владеет монопольной блокировкой по Таблице 2. Прежде чем будет освобождена любая монопольная блокировка, первой транзакции требуется блокировка по Таблице 2 и второй транзакции – требуется блокировка по Таблице 1. Теперь каждая транзакция ждет, пока другая транзакция освободит свою монопольную блокировку, но ни одна из транзакций не сделает этого, пока не будет выполнено фиксирование или откат для завершения соответствующей транзакции. Ни одна из транзакций не может завершиться, поскольку для продолжения работы ей требуется блокировка, которой владеет другая транзакция, – ситуация взаимоблокировки! Этот сценарий показан на рис. 19.2. При возникновении взаимоблокировки SQL Server прекращает одну из транзакций, и ее требуется запустить заново.

Цепное блокирование

Рис. 19.1. Цепное блокирование
 Взаимоблокировка

Рис. 19.2. Взаимоблокировка
Дополнительная информация. Для получения информации о том, как избежать ситуации блокирования и взаимоблокировки, найдите "Blocks" (Блокирование) в Books Online и выберите "Understanding and Avoiding Blocking" (Как избежать блокирования) в диалоговом окне Topics Found. Кроме того, найдите "Deadlocks" (Взаимоблокировки) в Books Online и выберите "Avoiding Deadlocks and Handling Deadlocks" (Как избегать взаимоблокировок и справляться с проблемой взаимоблокировок).

Подсказки блокировки

Подсказки блокировки – это ключевые слова T-SQL, которые можно использовать с операторами SELECT, INSERT, UPDATE и DELETE, чтобы задать для SQL Server использование предпочтительного типа блокировки на уровне таблицы для определенного оператора. Вы можете использовать подсказки блокировки для переопределения принятого по умолчанию уровня изолированности. Вам следует использовать этот метод только в случае абсолютной необходимости, поскольку ваша неаккуратность может привести к блокированию или взаимоблокировкам.

Рассмотрим ситуацию, где может оказаться полезным использование подсказок блокировки. Предположим, что вы используете для всех транзакций принятый по умолчанию уровень изолированности read uncommitted (чтение незафиксированных данных). При этом уровне изолированности по данному ресурсу захватывается разделяемая блокировка только до завершения чтения, и затем эта разделяемая блокировка освобождается. И если какая-либо транзакция читает одни и те же данные дважды, то результаты чтения могут не совпасть, поскольку другая транзакция могла захватить блокировку между первым и вторым чтениями и модифицировать эти данные.

Чтобы избежать проблемы повторяемости чтения, вы можете задать уровень изолированности serializable (упорядочиваемость), но это вынудит SQL Server захватить все разделяемые блокировки, необходимые для операторов SELECT во всех транзакциях, пока не будет завершена каждая транзакция. Иными словами, для целостности транзакций разделяемые блокировки будут захвачены по таблице, указанной в операторе SELECT любой транзакции. Если вы не хотите поддерживать упорядочиваемость для всех ваших транзакций, то можете добавить какую-либо подсказку блокировки для определенного запроса. Подсказка блокировки HOLDLOCK в операторе SELECT указывает SQL Server захват всех разделяемых блокировок по таблице, заданной в операторе транзакции SELECT, вплоть до конца этой транзакции – независимо от уровня изолированности. Тем самым при повторном чтении будет наблюдаться согласованность данных (они не будут изменены другой транзакцией). Использование подсказок блокировки не влияет на уровень изолированности для других транзакций.

Примечание. Оптимизатор запросов SQL Server автоматически определяет наиболее эффективный план исполнения и типы блокировок для запроса. И поскольку оптимизатор запросов автоматически выбирает подходящие тип или типы блокировок, подсказки блокировки следует использовать, если только они хорошо изучены и когда это абсолютно необходимо, иначе они могут отрицательным образом повлиять на параллельно выполняемые задачи.

В следующем списке дается описание существующих подсказок блокировки на уровне таблиц.

  • HOLDLOCK. Захватывает разделяемую блокировку до завершения транзакции, а не освобождает ее сразу после того, как уже не требуется соответствующая таблица, страница или строка данных. Эквивалентно использованию подсказки блокировки SERIALIZABLE.
  • NOLOCK. Применяется только к оператору SELECT. Не получает разделяемых блокировок и не поддерживает монопольных блокировок; читает данные, которые монопольно захвачены другой транзакцией. Эта подсказка позволяет читать нефиксированные данные ( dirty read ).
  • PAGLOCK. Используется для блокировки на уровне страницы там, где обычно используется блокировка на уровне таблицы.
  • READCOMMITTED. Выполняется сканирование с тем же поведением по блокировкам, как у транзакций, использующих уровень изолированности read committed (принятый по умолчанию уровень изолированности для SQL Server).
  • READPAST. Применяется только к оператору SELECT и только к строкам, блокированным с помощью блокировки на уровне строк. Пропускаются строки, блокированные другими транзакциями, которые обычно включаются в набор результатов; возвращает результаты без этих блокированных строк. Может использоваться только с транзакциями, выполняемыми на уровне изолированности read committed.
  • READUNCOMMITTED. Эквивалентно NOLOCK.
  • REPEATABLEREAD.Выполняется сканирование с тем же поведением по блокировкам, как у транзакций, использующих уровень изолированности repeatable read.
  • ROWLOCK.Используются блокировки на уровне строк вместо блокировки на уровне страниц или на уровне таблиц.
  • SERIALIZABLE.Выполняется сканирование с тем же поведением по блокировкам, как у транзакций, использующих уровень изолированности serializable. Эквивалентно HOLDLOCK.
  • TABLOCK.Используется блокировка на уровне таблиц вместо блокировки на уровне страниц или на уровне строк. SQL Server захватывает эту блокировку до завершения оператора.
  • TABLOCKX. Используется монопольная блокировка по таблице. Внимание! Эта подсказка препятствует доступу других транзакций к этой таблице.
  • UPDLOCK. Используются блокировки изменения вместо монопольных блокировок при чтении таблицы. Эта подсказка позволяет другим пользователям только читать данные и позволяет вам изменять эти данные; тем самым никакой другой пользователь не сможет модифицировать эти данные после того, как вы в последний раз прочитали их.

Вы можете объединять совместимые подсказки блокировки, такие как TABLOCK и REPEATABLEREAD, но вы не можете объединять конфликтующие подсказки, такие как REPEATABLEREAD и SERIALIZABLE. Чтобы задать подсказку блокировки на уровне таблиц, заключите эту подсказку в круглые скобки после имени таблицы в операторе T-SQL. Следующая последовательность является примером использования подсказок TABLOCKX в операторе SELECT:

USE pubs
SELECT COUNT(ord_num)
FROM sales (TABLOCKX)
WHERE ord_date > "Sep 13 1994"
GO

Подсказка TABLOCK сообщает SQL Server, что нужно захватить монопольную блокировку на уровне таблиц по таблице продаж (sales), пока не будет выполнен данный оператор. Эта подсказка обеспечивает, что никакая другая транзакция не сможет модифицировать данные в таблице sales, пока данный запрос подсчитывает заказы из этой таблицы. Будьте осторожны, используя этот вид подсказки, поскольку блокирование доступа других транзакций к этой таблице может приводить к ожиданию других транзакций, снижению времени отклика и цепному блокированию. И снова напомним: используйте подсказки блокировки на уровне таблиц только в случае абсолютной необходимости.

Заключение

В этой лекции вы ознакомились с транзакциями, включая ACID-свойства транзакции и режимы, используемые для задания начала и конца транзакции. Вы также узнали о возможностях управления блокировками SQL Server уровнях блокировок и режимах блокировок. Мы также ознакомились с блокированием, взаимоблокировками и применением подсказок блокировки. Теперь вы получили хорошее представление об основах транзакций и методах блокировки транзакций. "Расширенное описание T-SQL" расширяет описание T-SQL, представленное в "Создание и использование умолчаний, ограничений и правил" ; в этой лекции вы узнаете, как использовать операторы T-SQL INSERT, UPDATE и DELETE, а также другие операторы, которые могут вам потребоваться при написании транзакций и хранимых процедур.