alan_beaulieu-learning_sql-ru (865932), страница 41
Текст из файла (страница 41)
Если все проходит хорошо, транзакция фиксируется; однако если чтото не так,происходит откат транзакции, т. е. все внесенные с начала транзакцииизменения отменяются.С помощью транзакции программа гарантирует, что пятьсот долларовили останутся на сберегательном счету, или перейдут на текущий счетбез какойлибо возможности краха. Независимо от того, была ли транзакция зафиксирована или произошел откат, все ресурсы, занятые(например, блокировка записи) во время выполнения транзакции, позавершении транзакции высвобождаются.Конечно, если программе удается завершить оба выражения update, носервер выключается до того, как смогут выполниться commit или rollback, откат транзакции произойдет, когда сервер вернется в рабочийрежим. (Одна из задач, которую должен выполнить сервер перед возвращением в нормальный режим работы, – найти все незавершенныетранзакции, запущенные на момент выключения сервера, и выполнить их откат.)Запуск транзакцииСерверы БД обрабатывают создание транзакций одним из двух возможных способов:• Активная транзакция всегда присутствует для каждого сеанса работы с БД, поэтому нет ни необходимости, ни способа для явного234Глава 12.
Транзакции•начала транзакции. По завершении транзакции сервер автоматически начинает новую транзакцию для сеанса пользователя.Если транзакция не начата явно, отдельные SQLвыражения фиксируются автоматически независимо друг от друга. Чтобы начатьтранзакцию, сначала нужно запустить на выполнение команду.Из трех рассматриваемых серверов первый подход использует OracleDatabase, а Microsoft SQL Server и MySQL – второй.
Одно из преимуществ подхода Oracle к обработке транзакций в том, что даже в случаеодиночной SQLкоманды есть возможность сделать откат, если пользователя не удовлетворяет результат или он изменил свое мнение. Такимобразом, если вы забудете вставить блок where в выражение delete, останется возможность отменить неверные действия (разумеется, толькоесли вы осознаете, допив свой утренний кофе, что не хотели удалятьвсе 125 000 строк своей таблицы)). Однако при работе с MySQL и SQLServer, как только нажата клавиша Enter, изменения, осуществленныеSQLвыражением, становятся постоянными (и тогда только администратор БД сможет восстановить исходные данные из резервной копииили какимилибо иными средствами).Стандарт SQL:2003 включает команду start transaction (запуститьтранзакцию), предназначенную для явного начала транзакции.
MySQLсоответствует этому стандарту, а пользователи SQL Server должны вызывать команду begin transaction (начать транзакцию). Для обоих серверов, пока транзакция не начата явно, все операции выполняютсяв режиме автоматической фиксации (autocommit mode), т. е. серверавтоматически фиксирует отдельные выражения. Следовательно, можно принять решение об использовании транзакций и выполнить команду запустить/начать транзакцию или просто позволить серверуфиксировать отдельные выражения.Оба сервера, MySQL и SQL Server, позволяют отключать режим автоматической фиксации для отдельных сеансов. В этом случае серверыбудут вести себя в отношении транзакций точно так же, как Oracle Database. В SQL Server для отключения режима автоматической фиксации служит следующая команда:SET IMPLICIT_TRANSACTIONS ONMySQL позволяет отключить режим автоматической фиксации так:SET AUTOCOMMIT=0Если режим автоматической фиксации выключен, все SQLкомандывыполняются в рамках транзакции, и их фиксацию или откат следуетвыполнять явно.Рекомендация: при каждом входе в систему следует отключатьрежим автоматической фиксации.
Выполнение всех SQLвыражений в рамках транзакции должно войти в привычку. По крайЧто такое транзакция?235ней мере, это поможет вам избежать унизительной необходимости просить администратора БД восстановить уничтоженные понеосторожности данные.Завершение транзакцииЕсли транзакция запущена – явно посредством команды start transaction или неявно сервером БД, – пользователь должен явно завершитьее, чтобы внесенные им изменения стали постоянными. Это делаетсяс помощью команды commit, которая указывает серверу пометить изменения как постоянные и высвободить все ресурсы (т. е. снять блокировку страниц или строк), используемые во время транзакции.Если решено отменить все изменения, сделанные с момента началатранзакции, необходимо выполнить команду rollback, которая указывает серверу вернуть данные в то состояние, в каком они находилисьдо начала транзакции.
После завершения выполнения rollback все ресурсы, используемые сеансом, высвобождаются.Кроме выполнения команды commit или rollback, возможны еще несколько сценариев завершения транзакции – или как косвенный результат действий пользователя, или как результат чегото, находящегося вне власти пользователя:• Выключение сервера; в этом случае откат транзакции будет выполнен автоматически при возобновлении работы сервера.• Выполнение SQLвыражения управления схемой, например altertable, что приведет к фиксации текущей транзакции и запуску новой.• Выполнение еще одной команды start transaction, в результате чегопроисходит фиксация предыдущей транзакции.• Преждевременное завершение транзакции сервером, который выявил взаимоблокировку (deadlock) и решил, что виновна в этом данная транзакция.
В этом случае будет выполнен откат транзакциии пользователь получит сообщение об ошибке.Из этих четырех сценариев первый и третий довольно просты, а вот двадругих заслуживают некоторого внимания. Если говорить о второмсценарии, изменения базы данных, независимо от того, было ли это добавление новой таблицы, индексация или удаление столбца из таблицы, не могут быть отменены. Таким образом, команды, изменяющиесхему, должны выполняться вне транзакции. Поэтому если транзакция уже запущена, сервер зафиксирует ее, выполнит команду(ы)SQLвыражений управления схемой и затем автоматически запуститновую транзакцию для данного сеанса.
Сервер не будет информировать пользователя о происходящем, поэтому следует действовать аккуратно, чтобы выражения, составляющие единицу работы, невзначай не были разбросаны сервером по нескольким транзакциям.236Глава 12. ТранзакцииЧетвертый сценарий занимается выявлением взаимоблокировок. Взаимоблокировка происходит, когда две разные транзакции ожидают ресурсов, удерживаемых другой транзакцией. Например, транзакция Атолько что обновила таблицу account и ожидает блокировки записи длятаблицы transaction.
В это время транзакция В вставила строку в таблицу transaction и ожидает блокировки записи для таблицы account.Если случится, что обе транзакции изменяют одну и ту же страницуили строку (в зависимости от детализации блокировок, используемойсервером БД), каждая из них будет бесконечно ожидать, когда другаятранзакция завершит выполнение и высвободит необходимый ресурс.Серверы БД всегда должны быть настороже и выявлять такие ситуации, чтобы не остановиться полностью; при выявлении взаимоблокировки выбирается одна из транзакций (произвольно или по какомутокритерию) и осуществляется ее откат, чтобы дать возможность другойтранзакции продолжить выполнение.В отличие от обсуждавшегося ранее второго сценария, сервер БД сформирует ошибку и сообщит пользователю о том, что был сделан откатего транзакции изза выявления взаимоблокировки.
Например, приработе с MySQL будет получена ошибка #1213, сопровождаемая следующим сообщением:Message: Deadlock found when trying to get lock; try restarting transaction(Сообщение: Обнаружена взаимоблокировка при попытке блокировки;попытайтесь перезапустить транзакцию)Как предлагает сообщение об ошибке, разумным будет повторно запустить транзакцию, для которой был сделан откат изза выявлениявзаимоблокировки. Однако если взаимоблокировки становятся довольно частым явлением, вероятно, необходимо скорректировать приложения, осуществляющие доступ к БД, чтобы снизить вероятностьвзаимоблокировок (одна общепринятая стратегия – обеспечить, чтобыдоступ к ресурсам всегда осуществлялся в одном и том же порядке, например изменение данных счета выполнялось бы перед вставкой данных транзакции).Точки сохранения транзакцийВ некоторых случаях может возникнуть проблема, когда требуется откат транзакции, но не хочется отменять все, что было сделано в рамках этой транзакции.
Для таких ситуаций в транзакции можно установить одну или более точек сохранения (savepoints) и использоватьих для отката к определенному месту транзакции, а не откатыватьполностью к началу.Всем точкам сохранения должны быть присвоены имена, что позволитиметь несколько таких точек в одной транзакции. Создать точку сохранения my_savepoint можно так:SAVEPOINT my_savepoint;237Что такое транзакция?Чтобы сделать откат к определенной точке сохранения, просто выполняется команда rollback, за которой следуют ключевые слова to savepoint (к точке сохранения) и имя точки сохранения:ROLLBACK TO SAVEPOINT my_savepoint;Выбор механизма храненияДля низкоуровневых операций с БД, таких как извлечение изтаблицы конкретной строки по значению первичного ключа,Oracle Database и Microsoft SQL Server используют всего одинмеханизм хранения.