Como ativar transações aninhadas com o ADO.NET e o SQL Server?
-
27-09-2019 - |
Pergunta
Eu tenho uma pergunta semelhante a como Verifica Se você estiver em uma transação. Em vez de verificar, como permito transações aninhadas?
Estou usando o Microsoft SQL Server Database com o ADO.NET. Vi exemplos usando o T-SQL e exemplos de transações iniciando o uso de nomes iniciantes e usando nomes de transações. Ao chamar o Connection.BegIntransaction, chamo outra função na mesma conexão e chama BeginTransaction novamente, o que me dá a exceção:
SqlConnection does not support parallel transactions.
Parece que muitas variantes da Microsoft permitem isso, mas não consigo descobrir como fazê -lo com o meu arquivo .mdf.
Como permito transações aninhadas com um banco de dados do Microsoft SQL Server usando C# e ADO.NET?
Solução
O SQL Server como um todo não suporta transações aninhadas. Em T-SQL, você pode emitir um BEGIN TRAN
dentro de um anterior BEGIN TRAN
Mas isso é apenas por conveniência. É apenas a transação externa que conta. O cliente .NET para SQL Server (SqlConnection
) nem permite que você faça isso e lança essa exceção quando você tenta.
Outras dicas
É um equívoco comum que o SQL Server suporta transações aninhadas. Isso não. Abrir várias transações e depois chamar o commit não faz absolutamente nada. Você pode escrever um SQL de teste facilmente para experimentar você mesmo. A única opção aqui para emular uma transação aninhada é usar o SavePoints.
Devo acrescentar que a única coisa que importa é quando @@ Tran_Count atingir zero é o ponto em que apenas a transação externa será comprometida.
SqlConnection conn = new SqlConnection(@"Data Source=test;Initial Catalog=test;User ID=usr;Password=pass");
conn.Open();
var com = conn.CreateCommand();
com.CommandText = "BEGIN TRANSACTION";
com.ExecuteNonQuery();
com.CommandText = "BEGIN TRANSACTION";
com.ExecuteNonQuery();
com.CommandText = "INSERT INTO testTable (ParamName,ParamValue) values ('test','test');";
com.ExecuteNonQuery();
com.CommandText = "COMMIT TRANSACTION";
com.ExecuteNonQuery();
com.CommandText = "ROlLBACK TRANSACTION";
com.ExecuteNonQuery();
com.CommandText = "SELECT COUNT(*) FROM testTable ";
MessageBox.Show(string.Format("Found {0} rows.", com.ExecuteScalar()));