如何在ADO.NET和SQL Server中启用嵌套事务?

7
我有一个类似于如何检查是否在事务中的问题。与其进行检查,我该如何允许嵌套事务?
我正在使用Microsoft SQL Server数据库和ADO.NET。我看到过使用T-SQL和使用begin以及使用事务名称启动事务的示例。当调用connection.BeginTransaction时,我在同一连接中调用另一个函数,它再次调用BeginTransaction,这会导致异常:
SqlConnection does not support parallel transactions.

看起来许多 Microsoft 变体都允许这样做,但是我无法弄清如何在我的 .mdf 文件中实现。

如何使用 C# 和 ADO.NET 允许在 Microsoft SQL Server 数据库中进行嵌套事务?

3个回答

8

整个 SQL Server 并不支持嵌套事务。在 T-SQL 中,您可以在早期的 BEGIN TRAN 中发出一个 BEGIN TRAN,但这只是为了方便起见。只有外部事务才会被计算。SQL Server 的 .NET 客户端 (SqlConnection) 甚至不允许您这样做,并在尝试时抛出此异常。


我的主机说他们提供“Microsoft SQL 2008”。这是T-SQL吗?如果不是,T-SQL来自哪里?我只想让外部事务计数。‘Microsoft SQL 2008’不允许这样吗?(也许可以配置它不抛出异常?) - user34537
T-SQL 是微软的 SQL 标准变体,可在所有版本的 SQL Server 中运行。如果您想避免此异常,请在提交或回滚早期交易之前避免调用 BeginTransaction - 如果仍有未决交易,则无法开始交易。我建议您查看使用 TransactionScope(http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope(VS.80).aspx)而不是自己尝试管理它们。 - Daniel Renshaw
嗯,那不是同一件事。这段代码是用于sqlite的,我不确定它是否支持它(因为它似乎支持ado.net的所有功能)。但这听起来很奇怪,如果T-SQL在所有版本的SQL Server中都存在,那么我不应该拥有它并且不应该允许使用吗?那个功能将使我的生活更轻松。即使只有一个函数使用它(我想我可以摧毁它,因为它仅在初始化时使用一个连接,直到完成。) - user34537
1
T-SQL是SQL Server的SQL语言方言。SqlConnection使用T-SQL向SQL Server发出命令,但即使T-SQL允许您(表面上)嵌套事务,SqlConnection也不允许它。您可以通过SqlCommand自己发出“BEGIN TRAN”命令,但那样您将绕过.NET对事务的支持。 - Daniel Renshaw
嗯,知道了。谢谢,看起来最简单的解决方法是杀掉外部事务,因为它只被使用一次,并且存在于sqlite中以获得更好的性能(它只运行一次,所以并没有太大的提升)。 - user34537

4

有一个普遍的误解,即SQL Server支持嵌套事务。实际上并不支持。打开多个事务然后调用提交操作完全没有意义。您可以很容易地编写一些测试SQL语句来验证这一点。在这里模拟嵌套事务的唯一选项是使用Savepoints。

我应该补充说明的是,只有在@@TRAN_COUNT达到零时,外部事务才会被提交。


0
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()));

2
这个答案可以从您运行它后发现的内容方面进行一些评论,这样会更有帮助。 - jocull

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接