16+
ComputerPrice
НА ГЛАВНУЮ СТАТЬИ НОВОСТИ О НАС




Яндекс цитирования


Версия для печати

Модуль поиска не установлен.

Транзакции

12.08.2003

Тульчинский Антон Викторович antontul@rambler.ru


Введение

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

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

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

Все транзакции должны обладать следующими четырьмя свойствами (известными как свойства АСИД):

Атомарность (Atomicity). Транзакция либо фиксирует результат своей операции, либо возвращает всё на место. Если транзакция выполняется успешно, результат транзакции фиксируется. Если по какой-то причине транзакция не удалась, объекты, над которыми осуществлялась операция, возвращаются в исходное состояние. Например, при переименовании объекта должно произойти стирание старого имени и установка нового, или имя объекта должно остаться неизменным.

Кстати, атомарность (взаимозависимость) является неотъемлемой частью нашей повседневной жизни. К примеру, священник во время проведения церемонии бракосочетания сначала спрашивает жениха и невесту: "Хочешь ли ты взять себе в супруги этого человека?". Только после того как и тот и другая ответят "Да", священник может сказать: "Объявляю вас мужем и женой", и таким образом зафиксировать переход из одного состояния в другое. Другими словами, в рамках транзакции несколько независимых друг от друга участников сделки должны прийти к общему для всех соглашению, прежде чем сделка будет заключена. Если одна из сторон будет против, каждый из участников остаётся при своих.

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

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

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

Долговечность или устойчивость (Durability). Если транзакция завершилась успешно, её результат будет зафиксирован и сохранён. Более того, в этом случае результат сохранится даже при опасности возникновения сбоя системы.Следует отметить, что свойства АСИД транзакций не всегда выполняются в полном объеме. Особенно это относится к свойству И (изоляция). В идеале, транзакции разных пользователей не должны мешать друг другу, т.е. они должны выполняться так, чтобы у пользователя создавалась иллюзия, что он в системе один. Простейший способ обеспечить абсолютную изолированность состоит в том, чтобы выстроить транзакции в очередь и выполнять их строго одну за другой. Очевидно, при этом теряется эффективность работы системы. Поэтому реально одновременно выполняется несколько транзакций.

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

Свойство Д (долговечность) также не является абсолютными свойством, т.к. некоторые системы допускают вложенные транзакции. Если транзакция Б запущена внутри транзакции А, и для транзакции Б подана команда COMMIT WORK, то фиксация данных транзакции Б является условной, т.к. внешняя транзакция А может откатиться. Результаты работы внутренней транзакции Б будут окончательно зафиксированы, только если будет зафиксирована внешняя транзакция А.

Начало и завершение

Транзакция обычно начинается автоматически с момента присоединения пользователя к СУБД (обычно, но не всегда: например, Visual FoxPro требует подать явную команду BEGIN TRANSACTION для того, чтобы начать новую транзакцию) и продолжается до тех пор, пока не произойдет одно из следующих событий:

- Подана команда COMMIT WORK (зафиксировать транзакцию).

- Подана команда ROLLBACK WORK (откатить транзакцию).

- Произошло отсоединение пользователя от СУБД.

- Произошел сбой системы.

Команда COMMIT WORK завершает текущую транзакцию и автоматически начинает новую транзакцию. При этом гарантируется, что результаты работы завершенной транзакции фиксируются, т.е. сохраняются в базе данных. Команда ROLLBACK WORK приводит к тому, что все изменения, сделанные текущей транзакцией, откатываются, т.е. отменяются так, как будто их вообще не было. При этом автоматически начинается новая транзакция. При отсоединении пользователя от СУБД происходит автоматическая фиксация транзакций.

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

Параллельная работа

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

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

Каким образом транзакции различных пользователей могут мешать друг другу? Различают три основные проблемы параллелизма:

- Проблема потери результатов обновления.

- Проблема незафиксированной зависимости (чтение "грязных" данных, неаккуратное считывание).

- Проблема несовместимого анализа.

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

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

W-W (Запись - Запись). Первая транзакция изменила объект и не закончилась. Вторая транзакция пытается изменить этот объект. Результат - потеря обновления.

R-W (Чтение - Запись). Первая транзакция прочитала объект и не закончилась. Вторая транзакция пытается изменить этот объект. Результат - несовместимый анализ (неповторяемое считывание).

W-R (Запись - Чтение). Первая транзакция изменила объект и не закончилась. Вторая транзакция пытается прочитать этот объект. Результат - чтение "грязных" данных.

Конфликты типа R-R (Чтение - Чтение) отсутствуют, т.к. данные при чтении не изменяются.

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

Решение проблем: блокировки

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

Монопольные блокировки (X-блокировки, eXclusive locks) - блокировки без взаимного доступа (блокировка записи). В отличие от них, разделяемые блокировки (S-блокировки, Shared locks) - блокировки с взаимным доступом (блокировка чтения). Если транзакция A блокирует объект при помощи X-блокировки, то всякий доступ к этому объекту со стороны других транзакций отвергается. Если транзакция A блокирует объект при помощи S-блокировки, то запросы со стороны других транзакций на X-блокировку этого объекта будут отвергнуты, запросы со стороны других транзакций на S-блокировку этого объекта будут приняты.

Тупики

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

Можно представить два принципиальных подхода к обнаружению тупиковой ситуации и выбору транзакции-жертвы: СУБД не следит за возникновением тупиков. Транзакции сами принимают решение, быть ли им жертвами. Этот подход характерен для так называемых настольных СУБД (FoxPro и т.п.). Этот метод является более простым и не требует дополнительных ресурсов системы. Для транзакций задается время ожидания (или число попыток), в течение которого транзакция пытается установить нужную блокировку. Если за указанное время (или после указанного числа попыток) блокировка не завершается успешно, то транзакция откатывается (или генерируется ошибочная ситуация). За простоту этого метода приходится платить тем, что транзакции-жертвы выбираются, вообще говоря, случайным образом. В результате, из-за одной простой транзакции может откатиться очень дорогая транзакция, на выполнение которой уже потрачено много времени и ресурсов системы.

Второй подход к обнаружению тупиков заключается в том, что за возникновением тупиковой ситуации следит сама СУБД, она же принимает решение, какой транзакцией пожертвовать. Этот способ характерен для промышленных СУБД (ORACLE, MS SQL Server и т.п.). В этом случае система сама следит за возникновением ситуации тупика путем построения (или постоянного поддержания) графа ожидания транзакций (ориентированный двудольный граф, в котором существует два типа вершин - вершины, соответствующие транзакциям, и вершины, соответствующие объектам захвата). Ситуация тупика возникает, если в графе ожидания транзакций имеется хотя бы один цикл. Одну из транзакций, попавших в цикл, необходимо откатить, причем, система сама может выбрать эту транзакцию в соответствии с некими стоимостными соображениями (например, самую короткую, или с минимальным приоритетом и т.п.).

Транзакции в приложениях промышленного масштаба

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

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

Электронная коммерция: обеспечение безопасности транзакций

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

Транзакции различаются также по способу представления информации о карте в платежную систему. Существуют электронные транзакции (информация о карте считывается с магнитной полосы/чипа) и транзакции голосовой авторизации (paper based).

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

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

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

Для пластиковых карт с магнитной полосой самым надежным способом защиты транзакции от мошенничества является использование PIN-кода для идентификации владельца карты его банком-эмитентом. Секретной информацией, которой обладает владелец карты, является PIN-код. Он представляет собой последовательность, состоящую из 4-12 цифр, известную только владельцу карты и его банку-эмитенту. PIN-код применяется всегда при проведении транзакции повышенного риска, например при выдаче владельцу карты наличных в банкоматах. Выдача наличных в банкоматах происходит без присутствия представителя обслуживающего банка (ситуация похожа на транзакцию электронной коммерции). Поэтому обычных реквизитов карты для защиты операции "снятия наличных в банкомате" недостаточно и используется секретная дополнительная информация - PIN-код.

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

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

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

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

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

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

2. Реквизиты платежной карты (номер карты, срок ее действия, CVC2/CVV2 и т. п.), используемой при проведении транзакции, должны быть конфиденциальными для торговой точки.

3. Невозможность отказа от транзакции для всех участников транзакции, то есть наличие у всех участников неоспоримого доказательства факта совершения покупки (заказа или оплаты).

4. Гарантирование магазину платежа за электронную покупку - наличие у торговой точки доказательства того, что заказ был выполнен.

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

В заключение, я расскажу о двух средах, в которых "живут" транзакции. А именно, о реализации транзакций в InterBase и о сервисе "Java Transaction Service" технологии Enterprise JavaBeans.

Для управления транзакциями в InterBase имеется три выражения:

SET TRANSACTION - Начинает транзакцию и определяет ее поведение.

COMMIT - Сохраняет изменения, внесенные транзакцией, в базе данных и завершает транзакцию.

ROLLBACK - Отменяет изменения, внесенные транзакцией, и завершает транзакцию.

1. Запуск транзакции

Для запуска транзакции нужно выполнить следующую SQL-команду:

SET TRANSACTION [Access mode] [Lock Resolution] [Isolation Level] [Table Reservation]

Выражение "SET TRANSACTION"
равносильно выражению
"SET TRANSACTION READ WRITE WAIT ISOLATION LEVEL SNAPSHOT"

Access Mode - определяет тип доступа к данным. Может принимать два значения:

READ ONLY - указывает, что транзакция может только читать данные и не может модифицировать их.

READ WRITE - указывает, что транзакция может читать и модифицировать данные. Это значение принимается по умолчанию.

Isolation Level - определяет порядок взаимодействия данной транзакции с другими в данной базе. Может принимать значения:

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

SNAPSHOT TABLE STABILITY - предоставляет транзакции исключительный доступ к таблицам, которые она использует. Другие транзакции смогут только читать данные из них.

READ COMMITTED - позволяет транзакции видеть текущее состояние базы.

Конфликты, связанные с блокировкой записей, происходят в двух случаях:

Транзакция пытается модифицировать запись, которая была изменена или удалена уже после ее старта. Транзакция типа READ COMMITTED может вносить изменения в записи, модифицированные другими транзакциями после их завершения.

Транзакция пытается модифицировать таблицу, которая заблокирована другой транзакцией типа SNAPSHOT TABLE STABILITY.

Lock Resolution - определяет ход событий при обнаружении конфликта блокировки. Может принимать два значения:

WAIT - значение по умолчанию. Ожидает разблокировки требуемой записи. После этого пытается продолжить работу.

NO WAIT - немедленно возвращает ошибку блокировки записи.

Table Reservation - позволяет транзакции получить гарантированный доступ необходимого уровня к указанным таблицам. Существует четыре уровня доступа:

PROTECTED READ - запрещает обновление таблицы другими транзакциями, но позволяет им выбирать данные из таблицы.

PROTECTED WRITE - запрещает обновление таблицы другими транзакциями, читать данные из таблицы могут только транзакции типа SNAPSHOT или READ COMMITTED.

SHARED READ - самый либеральный уровень. Читать могут все, модифицировать - транзакции READ WRITE.

SHARED WRITE - транзакции SNAPSHOT или READ COMMITTED READ WRITE могут модифицировать таблицу, остальные - только выбирать данные.

2. Завершение транзакции

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

COMMIT - сохраняет внесенные транзакцией изменения в базу данных. Это означает, что транзакция завершена успешно.

ROLLBACK - откат транзакции. Транзакция завершается и никаких изменений в базу данных не вносится. Данная операция выполняется при возникновении ошибки при выполнении операции (например, при невозможности обновить запись).

Java Transaction Service

В качестве координатора транзакций в рамках архитектуры EJB (технология серверных компонентов, Enterprise JavaBeans) используется Java Transaction Service (JTS). В терминологии JTS этот координатор именуется как менеджер транзакций (transaction manager). Участники транзакции, реализующие транзактно-защищённые ресурсы типа релятивных баз данных, называются менеджерами ресурсов (resource managers). Когда приложение инициирует транзакцию, оно создаёт объект, который представляет эту транзакцию. Затем приложение обращается к менеджерам ресурсов, которые должны осуществить операцию. В процессе выполнения транзакции каждый из менеджеров транзакций отслеживает работу каждого из указанных в транзакции менеджеров ресурсов.

Первое обращение приложения к каждому из менеджеров ресурсов определяет текущую транзакцию. Например, если приложение использует релятивную базу данных, оно вызывает интерфейс JDBC (Java Database Connectivity), который связывает транзактный объект с базой данных. С этого момента все вызовы, осуществляющиеся через это соединение, будут выполняться от лица транзакции самой базы данных, до тех пор пока транзакция не завершится.

Приложение фиксирует результат транзакции путём вызова метода xa_commit() и сообщает, что транзакция была успешно завершена. Если же по какой-либо причине приложение не может завершить транзакцию, оно вызывает метод xa_rollback(), отменяющий те изменения, которые были произведены. В случае, если приложение не в состоянии выполнить транзакцию, JTS снимает задачу. Когда транзактная операция завершается успешно, приложение обращается к JTS, чтобы сохранить результат. Затем JTS проходит через двухфазный протокол фиксации транзакций, чтобы передать задание указанным в транзакции менеджерам ресурсов.

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



статьи
статьи
 / 
новости
новости
 / 
контакты
контакты