В двух предыдущих лекциях рассказывалось о том, как установить соединение с удаленными источниками данных. Для приложений, использующих распределенные клиенты, особенно важным является вопрос исключения перезаписи ввода одного пользователя другим пользователем. Как разработчик приложений, вы должны также гарантировать, что набор связанных изменений не будет нарушен, если эти изменения завершены лишь частично. Эти проблемы настолько важны для приложений баз данных в целом, что в данном курсе целая лекция посвящена тому, как SQL Server способствует их решению. В этой лекции объясняется, как упаковка изменений данных в транзакцию одновременно и препятствует тому, чтобы пользователи наступали друг другу на пятки, и дает разработчику приложений возможность обеспечить целостность данных.
Любой бизнес-процесс состоит из одной или нескольких транзакций. Представьте себе, что вы являетесь владельцем интернет-магазина. Когда клиент заказывает изделие, то, чтобы гарантировать своевременную доставку, должен запуститься предварительно заданный процесс. Этот процесс должен также предусматривать обработку кредитной карты, чтобы гарантировать получение оплаты вашей компанией. Если при выполнении одной из этих задач произойдет непоправимый сбой, то весь процесс необходимо отменить, чтобы не оказаться в ситуации, когда клиент получит счет, но не получит товар, и наоборот. В большинстве случаев такие процессы обрабатываются вычислительными системами, в которых все данные хранятся в базах данных. Данные, относящиеся к одной бизнес-транзакции, должны изменяться, чтобы оставаться доступными, согласованными и полными и отражать бизнес-процессы. Этого можно добиться, используя транзакции на уровне базы данных. Транзакцией называется последовательность операций, выполняемых, как один логический блок, и имеющая следующие свойства (так называемые свойства ACID):
Атомарность (Atomicity).Каждая транзакция представляет собой единицу работы. Она не может быть разбита на меньшие части. Это свойство означает, что выполняются либо все изменения данных, определенные в данной транзакции, либо не выполняется ни одно из них.
Согласованность (Consistency). Транзакция не может прервать ни одной из определенных в базе данных проверок на непротиворечивость. Для поддержания согласованности данных в процессе транзакции применяются все правила, проверки, ограничения и триггеры. Поскольку все изменения данных применяются на протяжении транзакции, гарантируется согласованность данных до начала транзакции и после ее завершения.
Изолированность (Isolation). Транзакции следует изолировать от изменений данных другими транзакциями. Это означает, что ни одна другая операция не должна изменять данные в промежуточном (незафиксированном) состоянии. Чтобы предохранить промежуточные данные от изменения, транзакция должна либо подождать подтверждения изменений данных другой транзакцией, либо видеть данные в подтвержденном ранее состоянии.
Устойчивость (Durability). После того, как транзакция завершается, и клиентское приложение получает уведомление об этом, изменения данных становятся устойчивыми независимо от любых системных сбоев.
Ядро базы данных SQL Server обеспечивает физическую целостность транзакции и живучесть транзакции посредством журнала транзакций. SQL Server также проводит все проверки на непротиворечивость по ограничениям, типам данных и т п., чтобы обеспечить логическую целостность. Вот и все действия, которые автоматически выполняет SQL Server. Однако для того, чтобы сопоставить бизнес-транзакциям транзакции SQL Server, разработчику придется очень внимательно отнестись к разработке некоторых транзакций.
Весь остальной материал данной лекции посвящен разработке и реализации транзакций в SQL Server.
Давайте посмотрим, как можно определить и обработать транзакции в SQL Server 2005. SQL Server предоставляет различные способы обработки транзакций, которые можно определить для каждого соединения с базой данных. Любое соединение может использовать тот режим, который необходим для выполнения специфических для этого соединения требований. Вот эти режимы:
SQL Server обрабатывает все изменения как транзакции. Никакое изменение данных не может произойти иначе, как в процессе транзакции. Следовательно, SQL Server приходится самому определять транзакцию, если она не определена разработчиком. Транзакции, определяемые SQL Server, называются также транзакцией с автофиксацией. Режим автофиксации используется SQL Server по умолчанию.
USE tempdb; GO CREATE TABLE table1 ( i int NOT NULL PRIMARY KEY, col1 varchar(20) NOT NULL, col2 varchar(20) NULL);
USE tempdb; GO INSERT INTO table1 (i,col1,col2) VALUES (1,'First row','First row'); INSERT INTO table1 (i,col1,col2) VALUES (2,NULL,'Second row'); INSERT INTO table1 (i,col1,col2) VALUES (3,'Third row','Third row');
USE tempdb; GO SELECT i,col1,col2 FROM table1;
Для явной транзакции разработчик определяет начало транзакции и момент, в который она должна быть зафиксирована или подвергнута откату. Это достигается при помощи инструкций T-SQL BEGIN TRANSACTION, COMMIT TRANSACTION и ROLLBACK TRANSACTION. Явные транзакции независимы от пакета. Явная транзакция может объединять несколько пакетов; в одном пакете может быть задано несколько явных транзакций.
USE tempdb; GO TRUNCATE TABLE table1;
USE tempdb; GO BEGIN TRAN INSERT INTO table1 (i,col1,col2) VALUES (1,'First row','First row'); INSERT INTO table1 (i,col1,col2) VALUES (2,NULL,'Second row'); INSERT INTO table1 (i,col1,col2) VALUES (3,'Third row','Third row'); COMMIT TRAN;
USE tempdb; GO SELECT i,col1,col2 FROM table1;
—выполняем усечение таблицы TRUNCATE TABLE table1 —транзакция с обработчиком ошибок BEGIN TRY BEGIN TRAN INSERT INTO table1 (i,col1,col2) VALUES (1,'First row','First row'); INSERT INTO table1 (i,col1,col2) VALUES (2,NULL,'Second row'); INSERT INTO table1 (i,col1,col2) VALUES (3,'Third row','Third row'); COMMIT TRAN; END TRY BEGIN CATCH ROLLBACK TRAN END CATCH;
В этом случае вы не получите сообщения об ошибке, поскольку ошибка была захвачена блоком CATCH.
USE tempdb; GO SELECT i,col1,col2 FROM table1;
Эта инструкция не возвратила ни одной записи. Как видите, произошел откат всей транзакции. Когда во второй инструкции INSERT произошло нарушение, SQL Server перешел к блоку CATCH и выполнил откат транзакции.
BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_SEVERITY() AS ErrorSeverity, ERROR_STATE() as ErrorState, ERROR_PROCEDURE() as ErrorProcedure, ERROR_LINE() as ErrorLine, ERROR_MESSAGE() as ErrorMessage; RAISERROR("Error in Transaction!",14,1) ROLLBACK TRAN END CATCH;
BEGIN CATCH DECLARE @er nvarchar(max) SET @er = "Error: "+ ERROR_MESSAGE(); RAISERROR(@er,14,1); ROLLBACK TRAN END CATCH;