Quelle est la raison du “contexte de Transaction en cours d'utilisation par une autre session”

Je suis à la recherche d'une description de la racine de cette erreur: "le contexte de Transaction en cours d'utilisation par une autre session".

Je reçois parfois à l'un de mes unittests donc je ne peux pas le fournisseur de repro code. Mais je me demande ce qu'est "by design" raison de l'erreur.

Mise à JOUR: l'erreur renvoie comme SqlException à partir de SQL Server 2008. Un endroit où je reçois le message d'erreur semble être mono-thread. Mais j'ai probablement unittests interaction que je reçois l'erreur où exécuter plusieurs tests à la fois (MSTest dans VS2008sp1).
Mais le test en échec ressemble:

  • créer un objet et de l'enregistrer à l'intérieur de DB-transaction (commit)
  • créer TransactionScope
  • en essayant d'ouvrir une connexion, ici, je reçois SqlException avec de tels 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()

J'ai trouvé ces postes:

Mais je ne peux pas comprendre ce que "Plusieurs threads partage la même opération dans une étendue de la transaction sera la cause de l'exception suivante:" les Transactions contexte en cours d'utilisation par une autre session.'" les moyens. Tous les mots sont compréhensibles, mais pas le point.

Fait, je peux partager un système de transaction entre les threads. Et il y a même mécanisme spécial pour ce - DependentTransaction de classe et de Transaction.DependentClone méthode.

Je suis en train de reproduire un cas d'utilisation à partir du premier post:

  1. Thread principal crée transaction DTC, reçoit DependentTransaction (créé à l'aide de la Transaction.Actuel.DependentClone sur le thread principal
  2. Enfant thread 1 enrôle dans cette transaction DTC par la création d'une étendue de transaction basée sur la transaction dépendante (adoptée par le constructeur)
  3. Enfant thread 1 ouvre une connexion
  4. Enfant thread 2 enrôle dans la transaction DTC par la création d'une étendue de transaction basée sur la transaction dépendante (adoptée par le constructeur)
  5. Enfant thread 2 ouvre une connexion

avec ce code:

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);
}
}

Il ne parvient pas à Terminer l'appel de la racine TransactionScope. Mais l'erreur est différente:
Exception Non Gérée: System.Des Transactions.TransactionInDoubtException: La transaction est mise en doute. --->
pired. Le délai écoulé avant la fin de l'opération ou le serveur ne répond pas.

Pour résumer: je veux comprendre ce "contexte de Transaction en cours d'utilisation par une autre session" signifie et comment le reproduire.

Un petit point: êtes-vous sûr que vous avez une transaction distribuée? Vous faites 2 ouvrir la connexion: con1.Open(); con2.Open(); Mais la connestion chaîne est la même et que vous utilisez Sql2008. Autant que je sache, si vous utilisez Sql2008 ET la même chaîne de connexion, la transaction ne dégénèrent pas distribué. Il reste "local". Mes 2 cents.
Non, l'ouverture de deux connexions simultanées conduit toujours à une transaction distribuée. Il n'a pas d'importance, ils ont les mêmes chaînes de connexion ou pas
mon erreur. Désolé.
mais vous avez raison dans le cas où si la même connexion instance s'ouvre et se ferme en série puis en sql2008 nous les tran mais dans sql2005 distibuted tran.

OriginalL'auteur Shrike | 2010-05-18