transaction transacciones tran stored procedimientos example begin and almacenados sql-server-2008 transactions transactionscope system.transactions

sql server 2008 - transacciones - ¿Por qué se compromete una transacción anidada incluso si nunca se llama a TransactionScope.Complete()?



transaction and rollback in sql server (2)

En primer lugar, no existe una transacción anidada en SQL Server . Esto es importante.

En segundo lugar, ambos tipos de TransactionScopes usan conn1, por lo que está (en el nivel de SQL Server) incrementando @@TRANCOUNT para cada BEGIN TRANSACTION

Explicación simple: la transacción interna se confirma cuando la transacción externa se compromete porque retroceder internamente revertiría ambas transacciones

Es decir, COMMIT TRANSACTION (implícita en .Complete y .Dispose ) disminuye @@TRANCOUNT mientras que ROLLBACK TRANSACTION (implícita en .Dispose only) lo lleva de vuelta a cero. Por lo tanto, la reversión interna se suprime debido a "no hay transacciones anidadas"

Si hubiera usado conn2 correctamente en el alcance interno, funcionaría como se esperaba porque las 2 transacciones no están relacionadas en el nivel del servidor de la base de datos. Que es donde importa ...

Estaba probando para ver cómo funcionan las transacciones anidadas, y descubrí este comportamiento inquietante e inesperado.

using(TransactionScope otx = new TransactionScope()) using(SqlConnection conn1 = new SqlConnection("Server=S;Database=DB;Trusted_Connection=yes")) using(SqlCommand cmd1 = conn1.CreateCommand()) { conn1.Open(); cmd1.CommandType = CommandType.Text; cmd1.CommandText = "INSERT INTO FP.ACLs (ChangeToken,ACL) VALUES (1,0x)"; cmd1.ExecuteNonQuery(); using(TransactionScope itx = new TransactionScope(TransactionScopeOption.RequiresNew)) using(SqlConnection conn2 = new SqlConnection("Server=S;Database=DB;Trusted_Connection=yes")) using(SqlCommand cmd2 = conn1.CreateCommand()) { conn2.Open(); cmd2.CommandType = CommandType.Text; cmd2.CommandText = "INSERT INTO FP.ACLs (ChangeToken,ACL) VALUES (2,0x)"; cmd2.ExecuteNonQuery(); // we don''t commit the inner transaction } otx.Complete(); // nonetheless, the inner transaction gets committed here and two rows appear in the database! }

Vi esta otra pregunta , pero la solución no se aplicaba.

Si no especifico TransactionScopeOption.RequiresNew (es decir, no utilizo una transacción anidada, solo un ámbito anidado), se revierte toda la transacción cuando el alcance interno no se completa y se produce un error al llamar a otx.Complete (). Esto esta bien.

¡Pero ciertamente no espero que se comprometa una transacción anidada cuando no se completó correctamente! ¿Alguien sabe lo que está pasando aquí y cómo puedo obtener el comportamiento esperado?

La base de datos es SQL Server 2008 R2.


Su segundo objeto Command se está creando en conn1 , no en conn2 , por lo que es muy parecido a la otra pregunta: la conexión en la que está ejecutando el comando se abrió antes de que se abriera el segundo alcance de transacción.