Ооп бд объектно-ориентированная база данных - страница 10

^ 18.Транзакции. Откат изменений и целостность БД НА ПРИМЕРЕ InterBase (((
транзакции - это пакет запросов, который последовательно производит изменения БД и либо принимается, если все изменения записи подтверждены, либо отвергается, если хоть один запрос завершился неуспешно. Запросы могут состоять из операторов ^ SELECT / INSERT / UPDATE / DELETE, причем в контексте одной транзакции может быть как один такой запрос, так и множество запросов. Однако понятие "транзакция" гораздо глубже этого короткого определения.

Транзакции запускаются на стороне сервера, причем стартуют они только по приказу клиентского приложения. Завершают работу они также по приказу клиентского приложения, причем при успешном завершении транзакция подтверждается, а при неудаче - отвергается. В триггерах или процедурах вызвать старт транзакции невозможно.

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

Поясним эту суть на классическом примере перевода денег в банке с одного счета на другой.

Допустим, наша БД работает без транзакций, и нам нужно произвести упомянутый перевод. Тут мы можем поступить двумя разными способами:

  1. Вначале снимаем деньги с одного счета, затем добавляем их к другому счету.

  2. Вначале добавляем деньги к другому счету, затем снимаем их с первого счета.

Теперь предположим, что в середине этой операции произошел какой-то сбой: отключился сервер БД, например. В первом случае деньги будут потеряны - они ушли с одного счета, но не дошли до другого. Во втором случае деньги "размножатся" - появятся на втором счету, но при этом останутся и на первом. И в том, и в другом случае произойдет нарушение целостности БД - данные станут недостоверны.

Однако все SQL-серверы баз данных работают с применением транзакций. Еще говорят, что все изменения базы данных происходят в контексте одной или нескольких транзакций. InterBase не исключение, более того, InterBase предоставляет гораздо более гибкие инструменты для управления транзакциями, чем многие другие SQL-серверы. Если произошел какой то сбой при переводе денег, то транзакция не получила подтверждения, а база данных осталась в прежнем состоянии - целостность и достоверность БД не нарушились.

Более 20 лет назад исследователи Тео Хендер и Андреас Рютер опубликовали обзор, в котором описывали принципы поддержания целостности БД в много-клиентской среде. Эти принципы принято называть ACID (Atomicity, Consistency, Isolation, Durability - Атомарность, Согласованность, Изоляция и Устойчивость). Всетранзакции действуют по этим принципам.
^ Атомарность (Atomicity)
Атомарность подразумевает, что транзакция является единицей работы с базой данных. Внутри транзакции может происходить множество модификаций БД, однако транзакция действует по принципу "все или ничего". Когда транзакция подтверждается (Commit), то подтверждаются все изменения данных, сделанные в ее контексте. Когда она отвергается (откатывается, Rollback), то отвергаются и все изменения. В случае возникновения сбоя, система, восстанавливаясь, ликвидирует последствия транзакций, не успевших завершиться.
^ Согласованность (Consistency)
Под согласованностью понимается, что целостность базы данных не нарушится, несмотря на то, была ли подтверждена транзакция, или отвергнута. В результате выполнения транзакции база данных переходит из одного целостного и согласованного состояния в другое. В случае если транзакция отвергнута, изменений БД не происходит.

На стороне сервера за согласованность отвечают ограничения CHECK, ограничения ссылочной целостности и триггеры. Программист, тем не менее, должен тщательно спроектировать механизмы бизнес-логики.
^ Изолированность (Isolation)
В базе данных может выполняться множество транзакций одновременно. Бывает, что две, и более транзакции пытаются изменить одну и ту же запись. Чтобы гарантировать целостность данных, транзакции выполняются изолированно друг от друга. Можно сказать, что каждая транзакция работает со своей копией (версией) данных. Существует несколько степеней изолированности транзакций, о чем далее мы поговорим подробней.
^ Устойчивость (Durability)
Если транзакция завершается успешно, изменения, сделанные в ее контексте, должны быть устойчивыми и сохранятся, независимо от ошибок в другихтранзакциях, ошибок оборудования или аварийного завершения работы сервера. Другими словами, результаты работы успешно завершенной транзакции физически сохраняются в базе данных.
^ Неявный и явный старт транзакций
Все действия над базой данных, совершаемые в клиентском приложении, происходят внутри (в контексте) транзакции. В примерах предыдущих лекций мы соединяли клиентские приложения с базой данных, вообще не используя никаких транзакций. Однако это не значит, что их не было. Просто транзакциизапускались неявно, автоматически. Причем с параметрами, созданными Delphi "по умолчанию". В серьезных приложениях БД это недопустимо, так как может привести к многочисленным конфликтам.

Транзакцию можно стартовать и явно. Из стандартных механизмов доступа мы будем использовать, в основном, ^ InterBase Express (IBX). В приложении должен присутствовать как минимум, один компонент IBTransaction. С помощью этого компонента можно явно указать параметры транзакции, управлять стартом, подтверждением или откатом транзакции. Делается это с помощью следующих методов компонента:

Впрочем, компоненты доступа к данным неявно производят запуск транзакции, поэтому StartTransaction обычно пропускают. А вот подтверждение или откаттранзакции проверяют, как правило, в блоке try…except в клиентском приложении:

try

//какие то действия над данными...

IBTransaction1.Commit; //подтверждаем

Except

//произошла ошибка

ShowMessage('Невозможно выполнить операцию!');

IBTransaction1.Rollback; //делаем откат транзакции

end; //try

В данном примере, если транзакция прошла успешно, то данные нормально сохраняются. В случае какой-то ошибки выводится сообщение, и транзакцияоткатывается.
^ Как транзакция работает
В базе данных имеется специальная область, которая называется TIP (Transaction Inventory Page - Инвентарная Страница Транзакций). При старте транзакции, ей присваивается идентификатор (TID, Transaction ID) - инвентарный номер, который сохраняется в TIP. При этом у самой последней транзакции будет наибольший идентификатор. В TIP, помимо номера стартовавшей транзакции, сохраняется и ее состояние, которое может быть Active (В работе), Committed (Подтвержденная),Rolled Back (Отмененная, откат) и In Limbo (Неопределенная).

Активной называется транзакция, которая в настоящий момент выполняется.

Подтвержденной называется транзакция, которая успешно завершила свою работу, как правило, по команде ^ Commit.

Отмененной называют транзакцию, которая завершилась неудачно. При этом производится откат сделанных ей действий, как правило, командой RollBack.

Неопределенной транзакцией (Limbo) называют транзакцию, которая работает одновременно с двумя или более базами данных. При завершении такойтранзакции, InterBase совершает двухфазное подтверждение Commit, гарантируя, что изменения будут внесены либо во все БД, либо ни в одну. При этом подтверждения в базах данных будут даваться по очереди. Если в это время возникнет сбой системы, то может получиться, что в каких то БД изменения были сделаны, а в каких то нет. При этом транзакция переходит в неопределенное состояние, когда сервер не знает, следует ли подтвердить эту транзакцию, или откатить.

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

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

Если транзакция завершилась неуспешно, оригинал записи так и остается оригиналом.

Если же транзакция только читает запись, не пытаясь ее изменить, то для нее не создается собственной версии.

Однако могут возникать и конфликты транзакций. Предположим, что стартовала транзакция Т1. Она создала версию записи, и поменяла ее данные. В это время стартовала конкурирующая транзакция Т2, и создала версию той же записи. Поскольку Т1 еще не завершилась, Т2 при старте не могла видеть изменения данных, сделанные Т1, а значит, создала свою версию из старого оригинала. Теперь Т1 завершает работу по Commit. Как должен поступить InterBase? Если он пометит версию записи Т1 как оригинал, а старую запись, как удаленную, то в версии Т2 окажутся ложные данные! Действия InterBase в этом случае будут зависеть от параметров этих транзакций, о чем ниже мы поговорим подробней.

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

Таким образом, говорят, что InterBase имеет многоверсионную архитектуру (MGA - Multi Generation Architecture). Такая архитектура позволяет организовать работу с базой данных так, чтобы читающие пользователи не блокировали пишущих. Кроме того, при возникновении сбоев в системе, InterBase очень быстро восстанавливается, благодаря именно MGA. Кстати, InterBase является первым SQL-сервером, который поддерживает многоверсионную архитектуру.

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

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

Предположим, что стартовала транзакция Т1. Эта транзакция создала версию записи и модифицировала ее. Позже стартовала транзакция Т2, которая настроена так, чтобы видеть все изменения данных, даже не подтвержденные. Она обратилась к той же записи, а поскольку она желает видеть последние изменения, ей предоставляют версию транзакции Т1. Затем Т1 завершила свою работу, но Т2 пока еще работает с ее версией записи, следовательно, эту версию удалять нельзя.

В InterBase присутствует механизм удаления старых версий, который запускается новыми транзакциями. Новая транзакция, запрашивая запись, считывает все версии этой записи. При этом делается проверка на то, была ли транзакция, сделавшая эту версию, отменена (RollBack) или подтверждена (Commit). Еслитранзакция была отменена, значит, эта версия - мусор, который следует удалить. Если же имеется несколько версий, сделанных подтвержденными транзакциями, то актуальной считается версия с наибольшим идентификатором транзакций. Остальные версии считаются устаревшими и также подлежат удалению.

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

Поскольку на сервере одновременно может выполняться множество транзакций, имеется терминология определения этих транзакций.

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



0641603083953882.html
0641749325700282.html
0641877352606497.html
0642033209920103.html
0642162242231792.html