Локальные транзакции
Транзакции в ADO.NET используются, когда требуется связать несколько задач так, чтобы они выполнялись как одна единица работы. Например, пусть приложение выполняет две задачи. Во-первых, оно заносит в таблицу сведения о заказе. Во-вторых, обновляет таблицу, содержащую список товаров на складе, списывая заказанные элементы. При сбое любой задачи будет выполнен откат обоих изменений.
Определение типа транзакции
Транзакция считается локальной, если она состоит из одной фазы и обрабатывается непосредственно базой данных. Транзакция считается распределенной, если она координируется монитором транзакций и использует для разрешения транзакций резервные механизмы (например, двухфазную фиксацию).
Каждый из поставщиков данных платформа .NET Framework имеет собственный Transaction
объект для выполнения локальных транзакций. Если требуется выполнить транзакцию в базе данных SQL Server, выбирается транзакция System.Data.SqlClient. Для транзакции Oracle используйте поставщик System.Data.OracleClient. Кроме того, существует класс DbTransaction, доступный для написания независимого от поставщика кода с использованием транзакций.
Примечание.
Транзакции наиболее эффективны, когда выполняются на сервере. При работе с базой данных SQL Server, интенсивно использующей явные транзакции, следует рассмотреть возможность их записи в виде хранимых процедур при помощи инструкции Transact-SQL BEGIN TRANSACTION.
Выполнение транзакций с использованием одного соединения
В ADO.NET управление транзакциями осуществляется с помощью объекта Connection
. Инициировать транзакцию можно с помощью метода BeginTransaction
. После начала транзакции при помощи свойства Transaction
объекта Command
к ней можно прикрепить команду. Затем в зависимости от успеха или ошибки компонентов транзакции можно зафиксировать или откатить изменения, сделанные в источнике данных.
Примечание.
Метод EnlistDistributedTransaction
не должен использоваться для локальной транзакции.
Область действия транзакции ограничена соединением. В следующем примере выполняется явная транзакция, состоящая из двух отдельных команд в блоке try
. Команды выполняют инструкции INSERT в таблице Production.ScrapReason в образце базы данных SQLWorks SQL Server, которая фиксируется, если исключения не возникают. Код в блоке catch
откатит транзакцию, если возникнет исключение. При отмене транзакции или обрыве соединения до выполнения транзакции она откатывается автоматически.
Пример
Чтобы осуществить транзакцию, выполните указанные ниже действия.
Вызовите метод BeginTransaction объекта SqlConnection для отметки начала транзакции. Метод BeginTransaction возвращает ссылку на транзакцию. Эта ссылка назначается объектам SqlCommand, прикрепленным к транзакции.
Присвойте объект
Transaction
свойству Transaction объекта SqlCommand. Исключение вызывается, если команда выполняется при соединении с активной транзакцией, а объектTransaction
не был назначен свойствуTransaction
объектаCommand
.Выполните требуемые команды.
Для выполнения транзакции вызовите метод Commit объекта SqlTransaction, для завершения транзакции вызовите метод Rollback. Транзакция откатывается, если соединение закрывается или пропадает до выполнения метода Commit либо Rollback.
В следующем примере кода демонстрируется транзакционная логика с помощью ADO.NET с Microsoft SQL Server.
using (SqlConnection connection = new(connectionString))
{
connection.Open();
// Start a local transaction.
SqlTransaction sqlTran = connection.BeginTransaction();
// Enlist a command in the current transaction.
SqlCommand command = connection.CreateCommand();
command.Transaction = sqlTran;
try
{
// Execute two separate commands.
command.CommandText =
"INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')";
command.ExecuteNonQuery();
command.CommandText =
"INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')";
command.ExecuteNonQuery();
// Commit the transaction.
sqlTran.Commit();
Console.WriteLine("Both records were written to database.");
}
catch (Exception ex)
{
// Handle the exception if the transaction fails to commit.
Console.WriteLine(ex.Message);
try
{
// Attempt to roll back the transaction.
sqlTran.Rollback();
}
catch (Exception exRollback)
{
// Throws an InvalidOperationException if the connection
// is closed or the transaction has already been rolled
// back on the server.
Console.WriteLine(exRollback.Message);
}
}
}
Using connection As New SqlConnection(connectionString)
connection.Open()
' Start a local transaction.
Dim sqlTran As SqlTransaction = connection.BeginTransaction()
' Enlist a command in the current transaction.
Dim command As SqlCommand = connection.CreateCommand()
command.Transaction = sqlTran
Try
' Execute two separate commands.
command.CommandText = _
"INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')"
command.ExecuteNonQuery()
command.CommandText = _
"INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')"
command.ExecuteNonQuery()
' Commit the transaction
sqlTran.Commit()
Console.WriteLine("Both records were written to database.")
Catch ex As Exception
' Handle the exception if the transaction fails to commit.
Console.WriteLine(ex.Message)
Try
' Attempt to roll back the transaction.
sqlTran.Rollback()
Catch exRollback As Exception
' Throws an InvalidOperationException if the connection
' is closed or the transaction has already been rolled
' back on the server.
Console.WriteLine(exRollback.Message)
End Try
End Try
End Using