Локальные транзакции

Транзакции в 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 откатит транзакцию, если возникнет исключение. При отмене транзакции или обрыве соединения до выполнения транзакции она откатывается автоматически.

Пример

Чтобы осуществить транзакцию, выполните указанные ниже действия.

  1. Вызовите метод BeginTransaction объекта SqlConnection для отметки начала транзакции. Метод BeginTransaction возвращает ссылку на транзакцию. Эта ссылка назначается объектам SqlCommand, прикрепленным к транзакции.

  2. Присвойте объект Transaction свойству Transaction объекта SqlCommand. Исключение вызывается, если команда выполняется при соединении с активной транзакцией, а объект Transaction не был назначен свойству Transaction объекта Command.

  3. Выполните требуемые команды.

  4. Для выполнения транзакции вызовите метод 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

См. также