Создание транзакций область с Новое sqlconnection в пределах существующего объекта sqlconnection, используя блок


Я хочу выполнить один запрос SELECT, за которым следует последовательность запросов UPDATE (Все в одной таблице); UPDATE реализуется в отдельном методе, который вызывается повторно. Если один из запросов обновления завершается неудачей, я хочу, чтобы все они завершились неудачей/откатом - поэтому я хочу включить их в транзакцию. Однако я не уверен, где SqlConnection следует открывать, чтобы избежать каких-либо проблем. Моя текущая реализация выглядит следующим образом:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    // execute a single SELECT here

    using (TransactionScope scope = new TransactionScope())
    {
        for (int i=0; i<...; i++)
        {
            Update(); // UPDATE query
        }

        scope.Complete();
    }
}


Update()
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        // execute a single UPDATE here
    }
}
Должно ли это работать так, как ожидается, во всех ситуациях?

Все в порядке чтобы открыть соединение перед выбором, затем откройте новое соединение в методе Update()? Из-за объединения соединений одно и то же соединение будет использоваться для запросов SELECT и UPDATE (connectionString является одним и тем же), но только запросы UPDATE будут зачислены в транзакцию, верно? Но что происходит, если в Update() используется другое соединение? Будут ли все запросы обновления по-прежнему включаться в транзакцию, как ожидалось, и выполняться атомарно?

Если я правильно понимаю, создание области транзакций после закрытие первого соединения (после блока using, который выполняет SELECT) все еще будет работать, но снизит производительность, потому что соединение будет закрыто и его нужно будет снова открыть, правильно? Или на самом деле создается новое соединение для области транзакции, которое открывается и закрывается каждый раз, когда вызывается Update()?

1 3

1 ответ:

Из-за объединения соединений одно и то же соединение будет использоваться как для запросов SELECT, так и для запросов UPDATE

Нет, этого не произойдет; это может произойти только в том случае, если вы сначала отпустите соединение обратно в пул - в настоящее время у вас есть два соединения одновременно, поэтому это не может быть одно и то же. Вам нужно немного перестроиться:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    // execute a single SELECT here
} // <==== end the first connection

using (TransactionScope scope = new TransactionScope())
{
    for (int i=0; i<...; i++)
    {
        Update(); // UPDATE query
    }

    scope.Complete();
}

Создание области транзакции после закрытия первого соединения (...) но снизит производительность, потому что подключение был бы закрыт и должен быть вновь открыт, правильно

Нет; когда вы" закрываете " его, вы фактически просто отпускаете его обратно в пул; он не закрывает базовое соединение (если только у вас не отключен пул). Закрытие (или, по крайней мере, удаление) является нормальным и ожидаемым.

Но только запросы обновления будут зачислены в транзакцию, верно?

Правильно, потому что тогда это единственное место, где соединение открывается внутри области транзакции

Но что произойдет, если в Update () будет использовано другое соединение? Будут ли все запросы обновления по-прежнему включаться в транзакцию, как ожидалось, и выполняться атомарно?

Все соединения, поддерживающие подключение (при условии, что оно не отключено в строке подключения), будут подключены. Однако в зависимости от сервера он может использовать LTM или DTC. Если вы хотите быть уверены в своих связях: возьмите их под свой контроль:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    // execute a single SELECT here
} // <==== end the first connection

using (TransactionScope scope = new TransactionScope())
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    for (int i=0; i<...; i++)
    {
        Update(connection); // UPDATE query
    }

    scope.Complete();
}

Обратите внимание, что я передаю connection в Update в выше; здесь очевидно , что будет использоваться одно соединение (при условии, что Update работает нормально).