快照隔离事务由于更新冲突而中止,但没有事务开始

Posted

技术标签:

【中文标题】快照隔离事务由于更新冲突而中止,但没有事务开始【英文标题】:Snapshot Isolation Transaction aborted due to update conflict, but no transaction begins 【发布时间】:2015-10-20 09:36:13 【问题描述】:

我在执行 UPDATE 语句时遇到错误。

错误:

快照隔离事务由于更新冲突而中止。你 无法使用快照隔离直接访问表 'dbo.Companies' 或间接在数据库“myDatabase”中更新、删除或插入 已被另一个事务修改或删除的行。 重试事务或更改隔离级别 更新/删除语句。

声明:

UPDATE [ActiveSession] SET [LastActionExecutedAt] = GETDATE() WHERE [SessionID]=@id

我通过 ASP.NET 应用程序运行上述语句。

奇怪的是该语句是在没有事务的情况下执行的。 代码如下:

using(var sqlconn = new SqlConnection("connection string")
using(var sqlcmd = sqlconn.CreateCommand())

    sqlconn.Open();
    sqlcmd.Parameters.Add("@id", SqlDbType.NVarChar).Value = id;

    sqlcmd.CommandText = "SELECT * FROM [ActiveSession] WHERE @id=id";
    using(var sqlreader = sqlcmd.ExecuteReader())
    
        // read info
        reader.Close();
    

    sqlcmd.CommandText = "UPDATE ....";
    Sqlcmd.ExecuteNonQuery();

我google了一下,发现错误是在我使用SNAPSHOT隔离级别事务时发生的。但是没有交易。

正如this thread 中所述,INDEXING 在某些情况下会有所帮助,但这对我没有帮助。

关于这个错误的任何想法?任何帮助将不胜感激。

谢谢,

【问题讨论】:

总是一个事务。默认情况下,如果您执行 DML 语句并且没有打开事务,SQL Server 将打开一个,运行该语句,然后提交或回滚事务(取决于成功或错误)。见Autocommit transactions 谢谢 Damien,自动提交事务是否使用快照隔离级别?我将 ALLOW_SNAPSHOT_ISOLATION 设置为 ON,但 READ_COMMITTED_SNAPSHOT 设置为 OFF。在这种情况下,我认为带有快照隔离的事务需要像 ADO.NET (msdn) 这样的明确规范。 【参考方案1】:

如 Damien 所述,更新语句使用自动提交事务。

自动提交事务使用上次为连接声明的隔离级别而不是默认隔离级别(请参阅this question)。

这种行为使得更新语句同时在 READ COMMITTED 和 SNAPSHOT 隔离级别执行,这就是发生更新冲突的原因。

似乎这个问题在 SQL Server 2014 CU6 中已修复,但我仍然使用 2008 R2 :(

谢谢,达米安!

【讨论】:

以上是关于快照隔离事务由于更新冲突而中止,但没有事务开始的主要内容,如果未能解决你的问题,请参考以下文章

数据库的快照隔离级别(Snapshot Isolation)

精通Java事务编程-弱隔离级别之快照隔离和可重复读

精通Java事务编程-弱隔离级别之快照隔离和可重复读

读取提交的快照隔离和事务

使用快照隔离防止 SQL 视图被冗长的删除/插入事务阻塞

精通Java事务编程-可串行化隔离级别之可串行化的快照隔离