Какова причина “Контекста транзакции, используемого другой сессией”

Я ищу описание корня этой ошибки: "Контекст транзакции, используемый другой сессией".

Я иногда получаю его в одном из моих unittests, таким образом, я не могу размноженный код поставщика. Но интересно, что "дизайном" причина ошибки.

ОБНОВЛЕНИЕ: ошибка возвращается как SqlException из SQL Server 2008. Место, где я получаю ошибку, кажется, является однопоточным. Но вероятно у меня есть unittests взаимодействие, поскольку я получаю ошибку, где запущено несколько тестов сразу (MSTest в VS2008sp1). Но провальный тест похож:

  • создайте объект и сохраните его в транзакции DB (фиксация)
  • создайте TransactionScope
  • при попытке открыть соединение - здесь я получаю SqlException с таким stacktrace:

.

System.Data.SqlClient.SqlException: Transaction context in use by another session.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
   at System.Data.SqlClient.SqlInternalConnectionTds.PropagateTransactionCookie(Byte[] cookie)
   at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()

Я нашел эти сообщения:

Но я не могу понять то, что "Несколько потоков, совместно использующих ту же транзакцию в области транзакций, вызовут следующее исключение: 'Контекст транзакции, используемый другой сессией'". средства. Все слова понятны, но не точка.

Я на самом деле могу совместно использовать системную транзакцию между потоками. И существует даже специальный механизм для этого - класс DependentTransaction и Транзакция. Метод DependentClone.

Я пытаюсь воспроизвести вариант использования из первого сообщения:

  1. Основной поток создает транзакцию DTC, получает DependentTransaction (созданная Транзакция использования. Текущий. DependentClone на основном потоке
  2. Дочерний поток 1 поступает на службу в эту транзакцию DTC путем создания области транзакций на основе зависимой транзакции (передал через конструктора),
  3. Дочерний поток 1 открывает соединение
  4. Дочерний поток 2 поступает на службу в транзакцию DTC путем создания области транзакций на основе зависимой транзакции (передал через конструктора),
  5. Дочерний поток 2 открывает соединение

с таким кодом:

using System;
using System.Threading;
using System.Transactions;
using System.Data;
using System.Data.SqlClient;

public class Program
{
    private static string ConnectionString = "Initial Catalog=DB;Data Source=.;User ID=user;PWD=pwd;";

    public static void Main()
    {
        int MAX = 100;
        for(int i =0; i< MAX;i++)
        {
            using(var ctx = new TransactionScope())
            {
                var tx = Transaction.Current;
                // make the transaction distributed
                using (SqlConnection con1 = new SqlConnection(ConnectionString))
                using (SqlConnection con2 = new SqlConnection(ConnectionString))
                {
                    con1.Open();
                    con2.Open();
                }
                showSysTranStatus();

                DependentTransaction dtx = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
                Thread t1 = new Thread(o => workCallback(dtx));
                Thread t2 = new Thread(o => workCallback(dtx));
                t1.Start();
                t2.Start();
                t1.Join();
                t2.Join();

                ctx.Complete();
            }
            trace("root transaction completes");
        }
    }
    private static void workCallback(DependentTransaction dtx)
    {
        using(var txScope1 = new TransactionScope(dtx))
        {
            using (SqlConnection con2 = new SqlConnection(ConnectionString))
            {
                con2.Open();
                trace("connection opened");
                showDbTranStatus(con2);
            }
            txScope1.Complete();
        }   
        trace("dependant tran completes");
    }
    private static void trace(string msg)
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " : " + msg);
    }
    private static void showSysTranStatus()
    {
        string msg;
        if (Transaction.Current != null)
            msg = Transaction.Current.TransactionInformation.DistributedIdentifier.ToString();
        else
            msg = "no sys tran";
        trace( msg );
    }

    private static void showDbTranStatus(SqlConnection con)
    {
        var cmd = con.CreateCommand();
        cmd.CommandText = "SELECT 1";
        var c = cmd.ExecuteScalar();
        trace("@@TRANCOUNT = " + c);
    }
}

Это перестало работать на вызове Complete корневого TransactionScope. Но ошибка отличается: Необработанное исключение: Система. Транзакции. TransactionInDoubtException: транзакция вызывает сомнение.---> вырванный. Период тайм-аута протек до завершения операции, или сервер не отвечает.

Подводя итоги: Я хочу понять то, что "Контекст транзакции, используемый другой сессией" средства и как воспроизвести его.

14
задан Esteban Küber 20 May 2010 в 16:25
поделиться

3 ответа

Сделайте шаг назад и сосредоточьтесь больше на своем коде, а не на информации о нескольких потоках, плавающей вокруг.

Если ваш сценарий не включает многопоточность, он может относиться к частям, которые не закрыты так, как вы ожидаете.

Возможно, вызываемый вами sql-код не достигает этой инструкции транзакции фиксации. Или на этом уровне задействовано что-то еще. Возможно, вы использовали экземпляр SqlConnection, устанавливающий транзакцию в коде .net, и повторно используете тот же экземпляр в другом коде, который использует TransactionScope. Попробуйте добавить инструкции using (), где это необходимо, чтобы убедиться, что все закрыто так, как вы ожидаете.

1
ответ дан 1 December 2019 в 16:15
поделиться

"Несколько потоков используют один и тот же транзакция в области транзакции вызовет следующее исключение: 'Контекст транзакции используется другим session. '"

Звучит довольно просто. Если вы подключите два разных соединения к одной транзакции, а затем попытаетесь выполнить команды для каждого из двух соединений одновременно из разных потоков, может возникнуть конфликт.

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

2
ответ дан 1 December 2019 в 16:15
поделиться

Как я решаю эту проблему при построении Linq-запросов с несколькими объектами, я бы сделал конструктор для каждого класса, который принимает контекст данных, и соответствующий метод GetDataContext() в каждом классе. При объединении классов я бы создавал новые экземпляры классов, передавая GetContext() первого класса

  public class CriterionRepository : ICriterionRepository
    {

        private Survey.Core.Repository.SqlDataContext _context = new Survey.Core.Repository.SqlDataContext();

        public CriterionRepository() { }

        public CriterionRepository(Survey.Core.Repository.SqlDataContext context)
        {            
            _context = context;
        }

...


        public Survey.Core.Repository.SqlDataContext GetDataContext()
        {
            return _context;
        }

}
0
ответ дан 1 December 2019 в 16:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: