Поделиться через


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

Транзакции в 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 в образце базы данных SQL Server AdventureWorks, которые фиксируются, если исключения не возникают. Код в блоке 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

См. также