我收到一个
SqlConnection does not support parallel transactions.
异常,并且 这个答案 在连接尝试打开两个事务时提到了它。这正是我正在做的事情。我认为嵌套事务没问题(我使用 sqlite 作为原型)。
如何检查连接是否已在事务中?我正在使用 Microsoft SQL Server 数据库文件。
经过一番搜索,我发现了另一个Stack Overflow问题。 事实证明,您无法在 ADO.NET 中嵌套事务。 当您尝试时,您可能最终会启动两个不相关的事务,这会导致并行事务错误。
要查看连接当前是否处于事务中,您可以:
var com = yourConnection.CreateCommand();
com.CommandText = "select @@TRANCOUNT";
var trancount = com.ExecuteScalar();
这将返回嵌套事务的数量。
请注意,您可以手动嵌套事务,而不使用 SqlTransaction 对象。 例如:
var com = yourConnection.CreateCommand();
com.CommandText = "BEGIN TRANSACTION";
com.ExecuteNonQuery();
com.CommandText = "BEGIN TRANSACTION";
com.ExecuteNonQuery();
com.CommandText = "INSERT INTO TestTable (name) values ('Joe');";
com.ExecuteNonQuery();
com.CommandText = "COMMIT TRANSACTION";
com.ExecuteNonQuery();
com.CommandText = "ROlLBACK TRANSACTION";
com.ExecuteNonQuery();
com.CommandText = "SELECT COUNT(*) FROM TestTable";
Console.WriteLine("Found {0} rows.", com.ExecuteScalar());
这将打印
0
,因为嵌套事务已完全中止。
您是从多个线程执行此操作吗?如果是这样,那么询问将无济于事,因为在您询问的时间和开始新事务的时间之间,其他一些线程可能已经开始了自己的事务。您将需要使用连接池来避免这种竞争条件。
您可以通过检查
cmd.Transaction
是否为 null
来检查交易是否已打开。
然后相应地包装您的代码,以便如果事务已经打开,则调用函数拥有该事务并将适当地提交/回滚它。
//begin transaction unless one was already started
bool newTransaction = cmd.Transaction == null;
if (newTransaction) cmd.Transaction = cmd.Connection.BeginTransaction();
try {
// do Stuff Here
cmd.ExecuteNonQuery();
cmd.ExecuteNonQuery();
// commit if it's our to commit
if (newTransaction) cmd.Transaction.Commit();
} catch (SqlException ex) {
if (newTransaction && cmd.Transaction != null) cmd.Transaction.Rollback();
throw;
}
然后父函数可以传入一个命令,并可选择开始它自己的事务块,否则,将由被调用的函数创建并提交一个事务块。