Транзакции в Oracle

Управление транзакциями лежит в сердце работы базы данных Oracle Database. Для того чтобы огромное количество пользователей могли одновременно выполнять свои транзакции, СУБД должна обеспечивать управление транзакциями с минимальным числом конфликтов, гарантируя при этом целостность базы данных. Управление транзакциями гарантирует одновременный доступ к базе данных Оракл множеству пользователей, причем никто из них не может отменить результаты работы друг друга. Для начала дадим определение транзакции.

Транзакцией (transaction) называется логическая единица работы, состоящая из одного или более операторов SQL. Транзакции могут охватывать всю программу или только ее часть. Транзакция может выполнять одну операцию или целую последовательность операций над объектами базы данных, интерактивно или как часть программы. Транзакции начинаются неявно при каждом чтении или записи данных и завершаются оператором COMMIT или ROLLBACK.

В этой статье рассматриваются основы управления транзакциями Oracle. Материал начинается с объяснения транзакции в контексте реляционной базы данных, основных типов аномалий данных, а также стандартных уровней изоляции транзакций и реализации Oracle уровня изоляции READ COMMITTED (уровень чтения только зафиксированных данных) для поддержки согласованности и параллелизма.

Концепция сериализуемости (serializability) критически важна в обработке транзакций. Параллелизм придает реляционным базам данных необходимую мощь, а условия сериализуемости гарантируют параллелизм транзакций в базе данных Oracle Database. В этой статье блога будет показано, как Oracle использует двойную технику блокировки транзакций и многоверсионное управление параллельным доступом с применением записей журнала повторного выполнения для обеспечения сериализуемости в транзакциях. Еще одним компонентом управления транзакциями Oracle является средство автоматической блокировки, которое помогает повысить степень параллелизма.

Управление пространством отмены (undo space) — важная часть управления транзакциями, и в следующих статьях вы узнаете о средстве автоматического управления отменой (Automatic Undo Management — AUM). Вы также узнаете о том, как использовать мощные средства поддержки ретроспективы Oracle, которые помогут решать такие задачи, как,например, быстрое восстановление после логических ошибок. Подробно рассматриваются все ключевые средства поддержки ретроспективы Oracle — Flashback Query, Flashback Versions Query, Flash Transaction Query и Flashback Table, — которые помогают вести аудит и исправлять логические ошибки данных. Все перечисленные средства Flashback полагаются на данные отмены из табличного пространства отмены (undo tablespace).

Продолжительные транзакции чреваты риском сбоя из-за ошибок, связанных с недостатком пространства. Вы узнаете о том, как использовать новое средство Oracle Resumable Space Allocation для возобновления транзакций, которые были прерваны из-за ошибок, связанных с нехваткой места. Вы также научитесь применению автономных транзакций. Далее (в других статья) мы рассмотрим средство Oracle Workspace Manager, которое обеспечивает управление версиями в отношении данных таблиц.

 

Транзакции Oracle

Операторы DDL, запускаемые администратором базы данных, обработать не очень сложно. Команды DDL изменяют схему (что означает изменение словаря данных), которая содержит определения объектов и прочие связанные с ними метаданные базы данных. Операции языка DML (также именуемого языком запросов) — концепции совершенно иного рода. Большинство операторов DML извлекают данные из базы, а остальные модифицируют или вставляют новые данные. Обработка транзакций DML включает компиляцию и выполнение операторов SQL наиболее эффективным образом,с минимальной конкуренцией между несколькими транзакциями, при этом сохраняя целостность базы данных.

Транзакция начинается немедленно в начале первого исполняемого оператора SQL и продолжается во время выполнения всех последующих операторов SQL до тех пор,пока не произойдет одно из перечисленных ниже событий.

  • COMMIT. Если транзакция встречает оператор COMMIT, все изменения, произведенные до этой точки, фиксируются в базе данных и становятся постоянными.
  • ROLLBACK. Если транзакция встречает оператор ROLLBACK, то все изменения, произведенные до этой точки, отменяются.
  • Оператор DDL. Если пользователь запускает оператор DDL, такой как CREATE,DROP, RENAME или ALTER, то, прежде чем выполнить и зафиксировать результаты оператора DDL, Oracle сначала фиксирует все текущие операторы DML, которые являются частью транзакции. Это называется неявной фиксацией (implicit commit),поскольку фиксация операторов DML, предшествующих операторам DDL, не выполняется пользователем явно.
  • Нормальное завершение программы. Если программа завершается без ошибок, то все изменения неявно фиксируются в базе данных. В случае нормального “чистого” выхода из SQL*PLus база данных автоматически фиксирует все изменения,которые были произведены в данных на протяжении сеанса.
  • Ненормальное завершение программы. Если программа терпит крах или прерывается, то все проведенные ею изменения неявно отменяются базой данных.

В начале транзакции Oracle назначает ей сегмент отмены, куда записываются первоначальные данные перед каждой их модификацией посредством обновления или удаления. В случае операции вставки сегмент отмены сохраняет соответствующие идентификаторы ROWID. Первый оператор после завершения транзакции помечает начало новой транзакции. Далее мы подробно рассмотрим операторы управления транзакциями COMMIT и ROLLBACK.

 

Оператор COMMIT

Оператор COMMIT успешно завершает транзакцию. Все изменения, произведенные всеми операторами SQL с начала транзакции, записываются на постоянное хранение в базу данных. До выдачи оператора COMMIT изменения в данных другим транзакциям не видны.

Зафиксировать транзакцию можно с помощью любого из приведенных ниже операторов, делающих изменения постоянными: 

SQL> COMMIT;
SQL> COMMIT WORK;

Прежде чем Oracle издаст оператор COMMIT, в базе данных происходят следующие действия.

  • Oracle генерирует записи отмены в буферах сегмента отмены в SGA. Как вам должно быть известно, записи отмены содержат старые значения обновленных и удаленных строк таблиц.
  • Oracle генерирует вхождения журнала повторного выполнения в буферах журнала повторного выполнения в SGA.
  • Oracle модифицирует буферы базы данных в SGA.

На заметку! Перед выдачей оператора COMMIT модифицированные буферы базы данных могут быть записаны на диск. Аналогично, перед выдачей оператора COMMIT вхождения журнала повторного выполнения также могут быть записаны в журнал повторного выполнения.


Когда транзакция Oracle фиксируется, происходят описанные ниже события.

1. Таблицы транзакций в записях повторного выполнения помечаются уникальным системным номером изменения (system change number — SCN) зафиксированной транзакции.

2. Процесс-писатель журнала записывает информацию в журнал повторного выполнения на диске из буфера журнала повторного выполнения, вместе с SCN транзакции. В этот момент фиксация считается завершенной в Oracle.

3. Все удерживаемые Oracle блокировки освобождаются, и Oracle помечает транзакцию как зафиксированную.


На заметку! Если установить SQL*Plus-переменную AUTOCOMMIT в on, то Oracle автоматически завершит транзакцию, даже без явного оператора COMMIT.


Поведение оператора COMMIT по умолчанию, которое чаще всего применяется, состоит в использовании опций IMMEDIATE и WAIT.

  • IMMEDIATE или BATCH. С помощью опции IMMEDIATE писатель журнала немедленно переносит на диск записи журнала повторного выполнения для зафиксированной транзакции. Если вы предпочитаете, чтобы он вместо этого выполнял буферизацию их в памяти, откладывая запись до удобного момента, укажите опцию BATCH.
  • WAIT или NOWAIT. С помощью опции WAIT оператор COMMIT не возвращает успешно управления до тех пор, пока записи журнала повторного выполнения не будут успешно занесены на диск. Если вы хотите, чтобы COMMIT возвращал управление,не ожидая записи в журнал, примените опцию NOWAIT.

Как видите, поведение по умолчанию заключается в том, что после фиксации немедленно происходит операция ввода-вывода на диск, а это приводит к небольшой задержке при завершении транзакции. Для определенных типов длительных транзакций может понадобиться избежать такой задержки, связанной с частой записью в журнал повторного выполнения и ожиданием подтверждения этой операции.

Поведение по умолчанию изменяется с помощью параметра инициализации COMMIT_WAIT и COMMIT_LOGGING.

Используйте параметр COMMIT_WAIT для контроля момента, когда база данных сбрасывает информацию о фиксации в журнал повторного выполнения. Применяйте параметр COMMIT_LOGGING для управления пакетированием процесса записи журнала.

 

Оператор ROLLBACK

Оператор ROLLBACK отменяет, или откатывает, изменения, внесенные операторами SQL внутри транзакции, которая еще не была зафиксирована. После выдачи оператора ROLLBACK ни одно из изменений, проведенных в таблицах операторами SQL с момента начала транзакции, в базу данных не заносится. Можете откатить и всю транзакцию,откатив изменения, проведенные всеми операторами SQL внутри транзакции, запустив команду ROLLBACK, как показано ниже: 

SQL> ROLLBACK;

Также имеется возможность частичного отката транзакции за счет использования внутри транзакции точек сохранения (save points). Посредством точки сохранения совершается откат к последней команде SAVEPOINT

SQL> ROLLBACK TO SAVEPOINT POINT A;

Оператор SAVEPOINT работает как закладка для незафиксированных операторов в транзакции. Во втором из двух предыдущих примеров откат транзакции происходит только до точки A. Все, что предшествовало этой точке, будет зафиксировано.

Oracle использует записи отмены в табличном пространстве отмены для отката транзакций по команде ROLLBACK. Он также освобождает все удерживаемые блокировки и помечает транзакцию как завершенную. Если откат происходит к точке сохранения,то транзакция считается незафиксированной и ее можно продолжить.

Если во время выполнения оператора SQL возникает ошибка, то все изменения,проведенные им к этому моменту, автоматически откатываются. Это известно как откат на уровне оператора. Взаимоблокировкой (deadlock) называется условие, когда операторы SQL из двух сеансов конкурируют за один и тот же фрагмент данных. В такой ситуации Oracle автоматически откатывает один из операторов, чтобы разрешить взаимоблокировку.

 

Свойства транзакций

Транзакции в СУБД должны обладать четырьмя важными свойствами, которые обозначаются аббревиатурой ACID, означающей атомарность, согласованность, изоляцию и устойчивость (atomicity, consistency, isolation и durability). В общем случае управление транзакциями означает поддержку транзакций базы данных в соответствии со свойствами ACID.

Рассмотрим свойства транзакций более подробно.

  • Атомарность. Вся транзакция должна либо выполниться целиком, либо не выполниться вообще. То есть не может быть такого, что база данных выполнит только часть транзакции. Например, если был выдан оператор SQL, который должен удалить 1000 записей, то вся транзакция должна быть отменена (проведен ее откат), если база даст сбой после удаления 999 записей.
  • Согласованность. База данных всегда должна пребывать в согласованном состоянии. Например, в банковской транзакции, включающей снятие денег с депозитного счета и перенос на текущий счет, база не может просто добавить деньги на текущий счет и остановиться. Это привело бы к несогласованным данным, и свойство согласованности транзакций гарантирует, что база никогда не оставит данные в таком несогласованном состоянии. Все транзакции должны предохранять согласованность базы данных. Например, если требуется удалить идентификатор отдела из таблицы Department, то база данных не должна допустить такого действия, если в таблице Employees имеются сотрудники, относящиеся к удаляемому отделу.
  • Изоляция. Изоляция означает, что несмотря на параллельный доступ к базе данных множества транзакций, каждая из них должна проходить изолированно от остальных. Свойство изоляции транзакций гарантирует, что транзакция не увидит изменений, внесенных другими транзакциями, прежде чем первая транзакция будет зафиксирована. Это свойство обеспечивается механизмом параллелизма базы данных, о чем вы узнаете из следующего раздела данной статьи. Хотя параллельный доступ — неотъемлемый признак реляционной базы данных, техника изоляции создает впечатление, что пользователи выполняют транзакции последовательно,одну за другой. Далее мы обсудим, как Oracle реализует управление параллельным доступом, гарантируя атомарность и изоляцию индивидуальных транзакций в базе данных с параллельным доступом.
  • Устойчивость. Последнее из свойств ACID — устойчивость — гарантирует, что база данных сохранит результаты зафиксированной транзакции на постоянной основе. Как только транзакция завершена, база данных должна гарантировать,что ее результаты не будут потеряны. Это свойство обеспечивается механизмами восстановления базы данных, гарантируя сохранность всех зафиксированных транзакций. Как было показано ранее в статьях блога, Oracle использует протокол опережающей записи, который обеспечивает первоначальную запись всех изменений в журналы повторного выполнения на диск до их переноса в файлы на диске.

На заметку! Пользователи могут назначать транзакциям имена, чтобы облегчить слежение за ними, и это особенно оправдано для длительных транзакций. Например, используя утилиту LogMiner, можно просмотреть детали интересующей транзакции. В одной из будущих статей я расскажу об использовании утилиты LogMiner для облегчения отмены изменений DML. Присвоение имен транзакциям также облегчает пользователю возможность опроса деталей транзакции через столбец name в представлении V$TRANSACTION.


Управление параллелизмом транзакций

Для обеспечения согласованности данных каждый пользователь должен видеть непротиворечивый набор данных, включающий все изменения, которые проведены его транзакциями, а также транзакциями других пользователей. В однопользовательской базе данных Oracle достичь подобной согласованности элементарно. Однако реальные базы данных должны обеспечивать возможность проведения одновременных операций множеством пользователей, и это требование известно как параллельный доступ к данным (data concurrency). Неправильные отношения между транзакциями могут привести к несогласованности данных.

Параллелизм транзакций (transaction concurrency) достигается управлением одновременными транзакциями разных пользователей, не допуская никаких взаимных влияний между ними. Если вы — единственный пользователь базы данных, вам не приходится беспокоиться об управлении параллелизмом транзакций. Однако в большинстве случаев базы данных позволяют тысячам пользователей выполнять одновременно транзакции выборки, обновления, вставки и удаления записей в одной и той же таблице.

Одно из возможных решений управления параллелизмом заключается в блокировке всей таблицы на протяжении каждой операции, так что транзакции одного пользователя не влияют на транзакции остальных пользователей. Таким образом, каждый пользователь работает в изоляции, при этом в жертву приносится параллельный доступ к данным. Однако это означало бы существенное ограничение доступа к таблице. Как будет показано, Oracle не использует механизмов блокировки для сохранения согласованности данных, но блокировка выполняется в более ограничивающей манере, с целью обеспечения максимальной степени параллелизма.

Параллелизм, без сомнений, повышает пропускную способность СУБД Oracle, порождая одновременно специфический набор проблем, которые рассматриваются ниже.

Проблемы параллелизма

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

Проблема грязного чтения

Грязное чтение (dirty read) возникает, когда транзакция читает данные, обновленные продолжающимися активными транзакциями, которые еще не были зафиксированы в базе данных. Например, предположим, что транзакция A только что обновила значение столбца, и это значение теперь читается транзакцией B. Что если транзакция A произведет откат своих изменений — намеренно либо в результате прерывания по какой-то причине? В результате этого значение обновленного столбца также будет подвергнуто откату. К сожалению, транзакция B уже прочитала новое значение столбца, которое стало недействительным, поскольку отменено откатом транзакции A.


Совет. Описанной здесь проблемы можно избежать, если соблюдать простое правило: не позволять ни одной транзакции читать промежуточные результаты другой транзакции до того, как другая транзакция будет либо зафиксирована, либо отменена. Таким образом, чтения гарантированно будут согласованными.


Проблема фантомного чтения

Предположим, что вы читаете данные из таблицы (с помощью оператора SELECT),затем после некоторой паузы повторяете чтение, а между тем какой-то другой пользователь произвел вставку новых данных в таблицу. Поскольку второй запрос получит некоторые дополнительные строки, которые не были прочитаны в первый раз, такие чтения называются “фантомными”, и проблема получила название фантомного чтения (phantom read). Эта проблема вызвана появлением новых данных между двумя операциями базы данных в пределах одной транзакции.

Проблема потерянного обновления

Проблема потерянного обновления (lost update) вызвана транзакциями, пытающимися читать данные в процессе их обновления другими транзакциями. Скажем, транзакция A читает данные таблицы, пока они обновляются транзакцией B, и транзакция B успешно фиксируется. Если транзакция A прочитала данные перед тем, как транзакция B полностью завершилась, она может получить промежуточные данные. Аномалия потерянного обновления случается потому, что два пользователя обновляют одну и ту же строку, и поскольку второе обновление перекрывает первое, первое обновления теряется.

Разрешение транзакции читать и обновлять таблицу перед завершением другой транзакции приводит в таком случае к проблемам.

Проблема невоспроизводимого чтения

Когда транзакция обнаруживает, что данные, прочитанные ею ранее, модифицированы некоторой другой транзакцией, возникает проблема невоспроизводимого чтения (nonrepeatable read, fuzzy read). Предположим, что вы обращаетесь к данным таблицы в определенный момент времени, а затем обращаетесь к тем же данным чуть позже,только чтобы обнаружить, что значения данных во второй раз стали другими. Подобная несогласованность данных в пределах одной транзакции порождает проблему невоспроизводимого чтения.

Расписания и сериализуемость

Как видите, все проблемы с данными возникают из-за параллельного доступа — можно легко предположить, что транзакция, выполняющаяся в изоляции, всегда оставит базу данных в согласованном состоянии по ее завершении. Если база данных допускает параллельный доступ, то следует учитывать совокупный эффект всех транзакций на согласованность базы данных.

Для этого база данных использует расписание (schedule), которое представляет собой последовательность операций одной или более транзакций. Если все транзакции выполняются последовательно, друг за другом, то и расписание также будет последовательным (serial). Если база данных может произвести расписание, которое эквивалентно по своему эффекту последовательному расписанию, даже если оно может состоять из набора параллельных транзакций, такое расписание называется сериализуемым (serializable).Сериализуемое расписание состоит из последовательностей промежуточных операций базы данных, выведенных из нескольких транзакций, конечным результатом которых является согласованная база данных.

Как вы могли предположить, выведение такого расписания нелегко реализовать на практике. Однако пользователям не приходится самим заниматься механизмами сериализации, когда они используют свои транзакции. База данных Oracle автоматически выводит сериализуемые расписания посредством применения уровней изоляции и управления данными отмены. Теперь давайте рассмотрим эти важные концепции.

Вас заинтересует / Intresting for you:

Поддерживаемые Oracle типы дан...
Поддерживаемые Oracle типы дан... 5653 просмотров Валерий Павлюков Wed, 24 Oct 2018, 08:00:37
Видеокурс по администрированию...
Видеокурс по администрированию... 10462 просмотров Илья Дергунов Mon, 14 May 2018, 05:08:47
Транзакция базы данных Oracle
Транзакция базы данных Oracle 1791 просмотров Antoniy Tue, 21 Nov 2017, 13:18:46
Создание базы данных Oracle
Создание базы данных Oracle 18710 просмотров Александров Попков Wed, 14 Nov 2018, 12:44:39
Войдите чтобы комментировать

Fasenger аватар
Fasenger ответил в теме #8856 03 дек 2017 14:58
Пишу многопользовательское приложение на основе БД Oracle. Часто сталкиваюсь с проблемой потерянного обновления (lost update) при одновременной записи в базу. Ника не могу разобраться в чем дело и как обойти. Сейчас активно морщу лоб по теме транзакций в СУБД Oracle. Спасибо за статью. Может быть посоветуете еще какой-то материал (еще более подробный)?