Что такое транзакция в информатике сообщение
Транзакция - (англ. transaction) — группа последовательных операций с базой данных, которая представляет собой логическую единицу работы с данными. Транзакция может быть выполнена либо целиком и успешно, соблюдая целостность данных и независимо от параллельно идущих других транзакций, либо не выполнена вообще и тогда она не должна произвести никакого эффекта. Транзакция переводит базу данных из одного непротиворечивого состояния в другое.
Наиболее популярным примером транзакции, который помогает лучше понять ее суть и необходимость, является операция перечисления денежных средств между банковскими счетами.
Приведем одну из возможных последовательностей действий, нужных для выполнения этой операции:
1. Проверить доступность счета, с которого предполагается списать деньги, и достаточность средств на нём. Это операция чтения данных, возможно, из нескольких таблиц).
2. Проверить доступность счета, на который предполагается зачислить деньги (например, счет может быть закрыть, временно заблокирован и т. п.). Это также операция чтения данных.
3. Уменьшить значение остатка на счете-источнике. Это операция модификации данных.
4. Увеличить значение остатка на счете-получателе. Это операция модификации данных.
5. Создать запись о проведенной операции в журнале операций. Это операция создания новой записи.
Разумеется, поддержка механизма транзакций технически может быть и очень сложной – при наличии десятков и сотен пользователей и тысяч обращений к данным обеспечить независимость этих обращений друг от друга, а также возможность отмены операций и возврата базы данных к исходному состоянию непросто. Для реализации этого механизма могут задействоваться различные средства, но есть свойства, которыми должны обладать транзакции и поддерживающая их система. Обычно для обозначения этих свойств используют аббревиатуру ACID – Atomicity, Consistency, Isolation, Durability. В переводе на русский – Атомарность, Согласованность, Изолированность и Долговечность. Рассмотрим эти свойства подробнее.
Атомарность как раз и означает неделимость транзакции и требование либо выполнять ее целиком, либо не выполнять вообще. Выше мы уже достаточно сказали о необходимости этого свойства и нет необходимости расшифровывать это понятие далее.
Согласованность – достаточно сложное понятие, которое несколько шире понятия целостности данных. Если целостность данных – это выполнение всех имеющихся в БД ограничений целостности (внутризаписных, межзаписных, ограничений внешних ключей и так далее), то согласованность означает еще и соответствие базы данных бизнес-правилам. В частности, из ограничений целостности может следовать запрет на отрицательное значение остатка на счете (то есть, соответствующего атрибута), но, скажем, требования равенства списываемой и зачисляемой суммы при переводе средств со счета на счет – это уже бизнес-правило, которое при помощи ограничений целостности не выразить.
Как уже было сказано, предполагается, что транзакция переводит БД из одного согласованного состояния в другое, но обеспечить это должны программисты, задающие последовательность операций. Роль СУБД здесь – гарантировать, что все операции будут выполнены успешно (или не будут выполнены вообще). Кроме того, в процессе выполнения транзации БД может проходить через ряд несогласованных состояний (скажем, в приведенном выше примере с переводом средств система несогласованна после выполнения операции 3 до выполнения операции 4).
Изолированность – это свойство транзакции выполняться независимо друг от друга. То есть, в процессе выполнения одной транзакции другие не могут повлиять на результат ее выполнения. Обеспечение совершенной независимости транзакций друг от друга требует и соответствующих ресурсов, и отрицательно сказывается на скорости выполнения операций с данными, так что существует несколько, так называемых, уровней изолированности, которые будут рассмотрены далее.
Теперь, после рассмотрения понятия транзакции и ее основных свойств, мы можем перейти к обсуждению вопросов использования транзакций для реализации восстановления базы данных после сбоев и для организации параллельной работы нескольких пользователей.
Транзакция — это набор операций по работе с базой данных (БД), объединенных в одну атомарную пачку.
Транзакционные базы данных (базы, работающие через транзакции) выполняют требования ACID, которые обеспечивают безопасность данных. В том числе финансовых данных =) Поэтому разработчики их и выбирают.
Я расскажу о том, что такое транзакция. Как ее открыть, и как закрыть. И почему это важно — закрывать транзакцию. И тогда при написании запросов к базе у вас будет осознанное понимание, что происходит там, под капотом, и зачем же нужен этот обязательный коммит после апдейта.
Содержание
Что такое транзакция
Представьте, что вы решили послать другу 10 файликов в мессенджере. Какие есть варианты:
Кинуть каждый файлик отдельно.
Вроде бы разницы особой нет. Но что, если что-то пойдет не так? Соединение оборвется на середине, сервер уйдет в ребут или просто выдаст ошибку.
В первом случае ваш друг получит 9 файлов, но не получит один.
Чтобы обратиться к базе данных, сначала надо открыть соединение с ней. Это называется коннект (от англ. connection, соединение). Коннект — это просто труба, по которой мы посылаем запросы.
Чтобы сгруппировать запросы в одну атомарную пачку, используем транзакцию. Транзакцию надо:
Выполнить все операции внутри.
Как только мы закрыли транзакцию, труба освободилась. И ее можно переиспользовать, отправив следующую транзакцию.
Можно, конечно, каждый раз закрывать соединение с БД. И на каждое действие открывать новое. Но эффективнее переиспользовать текущие. Потому что создание нового коннекта — тяжелая операция, долгая.
При настройке приложения администратор указывает, сколько максимально открытых соединений с базой может быть в один момент времени. Это называется пул соединений — количество свободных труб.
Разработчик берет соединение из пула и отправляет по нему транзакцию. Как только транзакция закрывается (неважно, успешно она прошла или откатилась), соединение возвращается в пул, и его может использовать следующая бизнес-операция.
Как открыть транзакцию
Как закрыть транзакцию
Тут есть 2 варианта:
COMMIT — подтверждаем все внесенные изменения;
ROLLBACK — откатываем их;
Например, я пишу запрос:
Запрос выполнен успешно, хорошо! Теперь, если я сделаю select из этой таблицы, прям тут же, под своим запросом — он находит Иванова! Я могу увидеть результат своего запроса.
Но! Если открыть графический интерфейс программы, никакого Иванова мы там не найдем. И даже если мы откроем новую вкладку в sql developer (или в другой программе, через которую вы подключаетесь к базе) и повторим там свой select — Иванова не будет.
А все потому, что я не сделала коммит, не применила изменения:
Я могу добавить кучу данных. Удалить полтаблицы. Изменить миллион строк. Но если я закрою вкладку sql developer, не сделав коммит, все эти изменения потеряются.
На самом деле это удобно. Ведь если ты выполняешь сложную операцию, можно посмотреть на результат. Например, удаляем тестовые данные. Написали кучу условий из серии:
Удалили. Делаем select count — посмотреть количество записей в таблице. А там вместо миллиона строк осталось 100 тысяч! Если база реальная, то это очень подозрительно. Врядли там было СТОЛЬКО тестовых записей.
Тут может возникнуть вопрос — а зачем вообще нужен ROLLBACK? Ведь без коммита ничего не сохранится. Можно просто не делать его, и всё. Но тогда транзакция будет висеть в непонятном статусе. Потому что ее просто так никто кроме тебя не откатит.
Или другой вариант. Нафигачили изменений:
Следующая операция бизнес-логики берет это самое соединение и продолжает в нем работать. А потом делает коммит. Этот коммит относился к тем 3 операциям, что были внутри текущей транзакции. Но мы закоммитили еще и 10 других — тех, что в прошлый раз откатить поленились. Тех, которые делают базу неконсистентной.
Так что лучше сразу сделайте откат. Здоровей система будет!
Итого
Транзакция — набор операций по работе с базой данных, объединенных в одну атомарную пачку.
Одной операции всегда соответствует одна транзакция, но в рамках одной транзакции можно совершить несколько операций (например, несколько разных insert можно сделать, или изменить и удалить данные. ).
В некоторых системах транзакцию нужно открыть, в других она открывается сама. А вот закрыть ее нужно самостоятельно. Варианты:
COMMIT — подтверждаем все внесенные изменения;
ROLLBACK — откатываем их;
Делая комит, мы заканчиваем одну бизнес-операцию, и возвращаем коннект в пул без открытой транзакции. То есть просто освобождаем трубу для других. Следующая бизнес-операция берет эту трубу и фигачит в нее свои операции. Поэтому важно сделать rollback, если изменения сохранять не надо. Не откатите и вернете соединение в пул? Его возьмет кто-то другой и сделает коммит. Своих изменений, и ваших, неоткаченных.
Не путайте соединение с базой (коннект) и саму транзакцию. Коннект — это просто труба, операции (update, delete…) мы посылаем по трубе, старт транзакции и commit /rollback — это группировка операций в одну атомарную пачку.
См также:
Блокировки транзакций — что может пойти не так при одновременном редактировании
Заметка! T-SQL – это расширение языка SQL, реализованное в Microsoft SQL Server. Более подробно об этом можете почитать в статье – Что такое T-SQL. Подробное описание для начинающих.
Транзакции в T-SQL
Транзакция – это команда или блок команд (инструкций), которые успешно завершаются как единое целое, при этом в базе данных все внесенные изменения фиксируются на постоянной основе, или отменяются, т.е. все изменения, внесенные любой командой, входящей в транзакцию, будут отменены. Другими словами, если одна команда или инструкция внутри транзакции завершилась с ошибкой, то все, что было отработано перед ней, также отменяется, даже если предыдущие команды завершились успешно.
Транзакции очень полезны и просто незаменимы в тех случаях, когда Вам необходимо реализовывать бизнес логику в базе данных Microsoft SQL Server, которая предполагает многошаговые операции, где каждый шаг логически связан с другими шагами.
Чтобы понять, как работают транзакции и для чего они нужны, давайте рассмотрим классический пример, который наглядно показывает необходимость использования транзакций.
Допустим, у Вас есть хранимая процедура, которая осуществляет перевод средств с одного счета на другой, соответственно, как минимум у Вас будет две операции в этой процедуре, снятие средств, и зачисление средств, например, две инструкции UPDATE.
Но в каждой из этих операций может возникнуть ошибка и инструкция не выполнится. А теперь представьте, что первая инструкция снимает деньги, она выполнилась успешно, вторая инструкция зачисляет деньги и в ней возникла ошибка, без транзакции снятые деньги просто потеряются, так как они никуда не будут зачислены.
Чтобы этого не допустить, все SQL инструкции, которые логически что-то объединяет, в данном случае все операции, связанные с переводом средств, пишут внутри транзакции, и тогда, если наступит подобная ситуация, все изменения будут отменены, т.е. деньги вернутся обратно на счет.
Транзакции можно сочетать с обработкой и перехватом ошибок TRY…CATCH, иными словами, Вы отслеживаете ошибки в Вашем блоке инструкций и если они появляются, то в блоке CATCH Вы откатываете транзакцию, т.е. отменяете все изменения, которые были успешно выполнены до возникновения ошибки в транзакции.
Транзакции – это отличный механизм обеспечения целостности данных.
Свойства транзакции
У транзакции есть 4 очень важных свойства:
- Атомарность – все команды в транзакции либо полностью выполняются, и соответственно, фиксируются все изменения данных, либо ничего не выполняется и ничего не фиксируется;
- Согласованность – данные, в случае успешного выполнения транзакции, должны соблюдать все установленные правила в части различных ограничений, первичных и внешних ключей, определенных в базе данных;
- Изоляция – механизм предоставления доступа к данным. Транзакция изолирует данные, с которыми она работает, для того чтобы другие транзакции получали только согласованные данные;
- Надежность – все внесенные изменения фиксируются в журнале транзакций и данные считаются надежными, если транзакция была успешно завершена. В случае сбоя SQL Server сверяет данные, записанные в базе данных, с журналом транзакций, если есть успешно завершенные транзакции, которые не закончили процесс записи всех изменений в базу данных, они будут выполнены повторно. Все действия, выполненные не подтвержденными транзакциями, отменяются.
Команды управления транзакциями в T-SQL
В T-SQL для управления транзакциями существуют следующие основные команды:
- BEGIN TRANSACTION (можно использовать сокращённую запись BEGIN TRAN) – команда служит для определения начала транзакции. В качестве параметра этой команде можно передать и название транзакции, полезно, если у Вас есть вложенные транзакции;
- COMMIT TRANSACTION (можно использовать сокращённую запись COMMIT TRAN) – с помощью данной команды мы сообщаем SQL серверу об успешном завершении транзакции, и о том, что все изменения, которые были выполнены, необходимо сохранить на постоянной основе;
- ROLLBACK TRANSACTION (можно использовать сокращённую запись ROLLBACK TRAN) – служит для отмены всех изменений, которые были внесены в процессе выполнения транзакции, например, в случае ошибки, мы откатываем все назад;
- SAVE TRANSACTION (можно использовать сокращённую запись SAVE TRAN) – данная команда устанавливает промежуточную точку сохранения внутри транзакции, к которой можно откатиться, в случае возникновения необходимости.
Примеры транзакций в T-SQL
Давайте рассмотрим примеры транзакций, реализованные на языке T-SQL.
Исходные данные для примеров
Но сначала нам необходимо создать тестовые данные для нашего примера.
Для этого выполните следующую инструкцию.
Простой пример транзакции в T-SQL
В данном примере у нас всего две инструкции, которые изменяют данные, но допустим, что они взаимосвязаны, т.е. они обе обязательно должны выполниться вместе или не выполниться также вместе.
Поэтому мы решили эти инструкции объединить в одну транзакцию.
Сначала мы открываем транзакцию командой BEGIN TRANSACTION, далее пишем все необходимые инструкции, которые мы хотим объединить в транзакцию.
После этого командой COMMIT TRANSACTION мы сохраняем все внесенные изменения.
В данном случае у нас нет никаких ошибок, все инструкции выполнились успешно. Как результат, транзакция завершена также успешно и все изменения сохранены на постоянной основе командой COMMIT TRANSACTION.
Однако, если в любой из инструкций возникнет ошибка, транзакция не завершится, и все изменения не сохранятся.
При этом, стоит помнить о том, что ошибки с определённым уровнем серьезности, например, ошибки, связанные с нарушением ограничений, не влекут за собой автоматический откат всех изменений внесенных текущей транзакцией, поэтому всегда необходимо использовать или инструкцию SET XACT_ABORT ON, или обработку ошибок (допускается и совместное использование).
Например, если во второй инструкции мы попытаемся записать в столбец Price какое-нибудь текстовое значение, то у нас возникнет ошибка, и изменения, внесённые первой инструкцией, не зафиксируются на постоянной основе.
Пример транзакции в T-SQL с обработкой ошибок
В языке T-SQL существует механизм перехвата и обработки ошибок – конструкция TRY… CATCH.
Эту конструкцию можно использовать для отслеживания появления возможных ошибок внутри транзакции и в случае появления таких ошибок предпринять определенные действия.
Сначала мы открываем блок для обработки ошибок, затем открываем транзакцию командой BEGIN TRANSACTION, далее пишем наши инструкции, например, те же самые две инструкции UPDATE.
После этого закрываем блок TRY, открываем блок CATCH, в котором в случае возникновения ошибки мы откатываем все изменения командой ROLLBACK TRANSACTION. Также мы принудительно завершаем нашу инструкцию командой RETURN.
Если ошибок нет, то в блок CATCH мы, соответственно, не попадаем и у нас выполнится команда COMMIT TRANSACTION, которая сохранит все изменения.
В этом примере нет ошибок, поэтому транзакция завершена успешно.
А в этом примере мы намерено допускаем ошибку во второй инструкции. Поэтому управление передается в блок CATCH, где мы откатываем все изменения, возвращаем номер и описание ошибки и принудительно завершаем всю инструкцию командой RETURN.
Первая инструкция отработала нормально, но ее изменения не были сохранены, так как вторая инструкция выполнена с ошибкой.
Уровни изоляции транзакций в T-SQL
Во время выполнения транзакции все данные, над которыми производятся изменения, блокируются, до завершения транзакции, так как, когда один процесс изменяет данные, другой процесс не может одновременно изменять их. В SQL сервере существует механизм, который блокирует (изолирует) данные во время выполнения транзакции. У данного механизма есть несколько уровней изоляции, каждый из которых определяет степень блокировки данных.
Давайте подробней рассмотрим уровни изоляции.
READ UNCOMMITTED
READ COMMITTED
Этот уровень уже запрещает грязное чтение, в данном случае все процессы, запросившие данные, которые изменяются в тот же момент в другой транзакции, будут ждать завершения этой транзакции и подтверждения фиксации данных. Данный уровень по умолчанию используется SQL сервером.
REPEATABLE READ
SERIALIZABLE
SNAPSHOT и READ COMMITTED SNAPSHOT
Также существуют уровни изоляции, алгоритм которых основан на версиях строк, это
Иными словами, SQL Server делает снимок и хранит последние версии подтвержденных строк. В данном случае, клиенту не нужно ждать снятия блокировок, пока одна транзакция изменит данные, он сразу получает последнюю версию подтвержденных строк. Следует отметить, что уровни изоляции, основанные на версиях строк, замедляют операции обновления и удаления, так как перед этими операциями сервер делает и копирует снимок строк во временную базу данных.
SNAPSHOT – уровень хранит строки, подтверждённые на момент начала транзакции, соответственно, именно эти строки будут считаны в случае обращения к ним из другой транзакции. Данный уровень исключает повторяющееся и фантомное чтение примерно так же, как уровень SERIALIZABLE.
READ COMMITTED SNAPSHOT – этот уровень изоляции работает практически так же, как уровень SNAPSHOT, с одним отличием, он хранит снимок строк, которые подтверждены на момент запуска команды, а не транзакции, как в SNAPSHOT.
Побочные эффекты параллелизма
На основе вышеизложенного мы можем выделить несколько побочных эффектов, которые могут возникнуть в результате параллельного использования данных:
- Потерянное обновление (LostUpdate) – при одновременном изменении данных разными транзакциями одно из изменений будет потеряно;
- Грязное чтение (DirtyRead) – чтение неподтвержденных данных;
- Неповторяющееся чтение (Non-Repeatable Read) – чтение измененных данных в рамках одной транзакции;
- Фантомное чтение (Phantom Reads) – чтение записей, которые появились между началом и завершением транзакции.
Каждый из уровней изоляции устраняет определенные побочные эффекты. В таблице ниже приведены сводные данные.
Побочный эффект / Уровень изоляции | Потерянное обновление | Грязное чтение | Неповторяющееся чтение | Фантомные записи |
READ UNCOMMITTED | Устраняет | Не устраняет | Не устраняет | Не устраняет |
READ COMMITTED | Устраняет | Устраняет | Не устраняет | Не устраняет |
REPEATABLE READ | Устраняет | Устраняет | Устраняет | Не устраняет |
SERIALIZABLE | Устраняет | Устраняет | Устраняет | Устраняет |
SNAPSHOT | Устраняет | Устраняет | Устраняет | Устраняет |
READ COMMITTED SNAPSHOT | Устраняет | Устраняет | Устраняет | Устраняет |
Включение уровня изоляции в T-SQL
Для того чтобы включить тот или иной уровень изоляции для всей сессии, необходимо выполнить команду SET TRANSACTION ISOLATION LEVEL и указать название уровня изоляции.
Также для уровней SNAPSHOT и READ COMMITTED SNAPSHOT предварительно необходимо включить параметр базы данных ALLOW_SNAPSHOT_ISOLATION для уровня изоляции SNAPSHOT и READ_COMMITTED_SNAPSHOT для уровня READ COMMITTED SNAPSHOT.
Транзакция — это группа операций со следующими свойствами: атомарная, последовательная, изолированная и устойчивая (ACID). Поддержка транзакций позволяет разрабатывать новые типы приложений, одновременно упрощая процесс разработки и повышая надежность приложения. Оставшаяся часть этого раздела содержит сценарии, демонстрирующие потребность в этих свойствах, а затем таблицу, определяющую каждое свойство.
В атомарной группе операций каждая операция в группе должна быть выполнена или все их последствия должны быть отменены (также называют откатом). Например, перевод банка должен быть атомарным набором из двух операций: дебет из одной учетной записи и кредит в другую учетную запись. Дебет и кредит должны быть реализованы как атомарная группа. Если эти две операции не выполняются, то перемещение будет неудовлетворительным в пользу банка или держателя учетной записи.
Требование согласованности означает, что данные будут согласованы после транзакции (при условии, что мы начали с согласованной системой до транзакции). Для примера перемещения в банке можно определить согласованность, так как суммарный баланс учетной записи двух счетов должен быть константой. Чтобы реализовать согласованность в примере перемещения в банке, операции по дебету и кредиту просто должны быть для того же объема денег.
Еще один пример транзакции — обновление веб-сайта. Для веб-сайта электронной коммерции требуется, чтобы новая страница навигации по категории продуктов отображалась в точно то же время, что и страницы сведений о продукте, описывающие новые продукты. В этом случае необходимо обновить и добавить несколько записей каталога под управлением транзакции. Не только необходимо, чтобы обновления были атомарными, но также необходимо, чтобы клиент, который в настоящее время применяет покупку, не просматривает выполняющиеся обновления. Это пример свойства изоляции транзакций.
Свойство устойчивости требует, чтобы после завершения обновления его последствия сохранились даже при зависании системы. В предыдущем примере устойчивость может предоставляться просто путем обеспечения адекватного восстановления данных, чтобы все новые записи файловой системы, представляющие Добавление нового продукта на сайт, отображались после того, как система перестанет отвечать на запросы. Для этого требуется система с механизмами резервного копирования, восстановления и высокой доступности данных.
Гарантия атомарности транзакции, а также других свойств, имеется в любом количестве сбоев, включая сбои, происходящие на этапе восстановления предыдущей ошибки. В итоге система будет находиться в одном из двух состояний: все операции применены или ни одна из операций не была применена.
Свойства транзакции приведены в следующей таблице.
Термин | Описание |
---|---|
At | Либо все операции в транзакции выполнены, либо ни одна из операций не сохраняется. |
Стабильны | Если данные согласуются до начала транзакции, они будут согласовываться после завершения транзакции. |
Изолирован | Эффекты выполняемой транзакции скрыты от всех остальных транзакций. |
Надежно | Когда транзакция завершается, ее результаты сохраняются в постоянном виде и остаются в результате сбоя системы. |
Эти свойства гарантируют, что программное обеспечение может справляться с непредвиденными ошибками, так как оно может просто прервать транзакцию, когда непредвиденная ситуация предотвращает успешное завершение. Инфраструктура транзакций гарантирует откат всех эффектов прерванной транзакции, возвращая данные в целостное состояние. Таким образом, транзакционная система обеспечивает корректное восстановление после сбоев системы.
Для обеспечения свойств ACID система, которая поддерживает транзакции, должна иметь надежную возможность ведения журнала, которая может использоваться для фиксации или отката транзакций по мере необходимости. Дополнительные сведения см. в разделе Файловая система CLFS.
Читайте также: