0

当我们上周五发布时,我收到了一个我没有接受的错误。错误信息是:

could not execute update query[SQL: delete from dbo.MyTable where col1=? and col2=? and col3=? and col4=? and col5=?]

我的 C# 代码如下:

var hqlDelete = "DELETE MyTable m WHERE m.Col1 = :var_1 AND m.Col2 = :var_2 AND m.Col3= :var_3 AND m.Col4 = :var_4 AND m.Col5= :var_5";
var deletedEntities = session.CreateQuery(hqlDelete)
                             .SetString("var_1", variable1)
                             .SetString("var_2", variable2)
                             .SetString("var_3", variable3)
                             .SetString("var_4", variable4)
                             .SetString("var_5", variable5)
                             .ExecuteUpdate();
transaction.Commit();
session.Close();

现在,正如我所说,在接受测试时没有触发错误。此外,当我使用生产数据库(来自我的开发人员座位的代码)进行测试时,它也可以正常工作。

当我调用 Web 服务并向其发布“测量”时会触发代码。唯一的区别是我在测试时调用该服务,而在生产中,另一家公司将测量结果发送到 Web 服务。

我认为这可能与会话/交易的数量有关,但这并不能真正解释为什么变量会像?错误消息中那样显示。

有任何想法吗?我可以提供更多信息,以便您可以帮助我吗?

编辑:InnerExeption 是

{"Transaction (Process ID 68) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction."}

4

1 回答 1

1

解决死锁可能是一件困难的事情,尤其是在使用 ORM 时。死锁通常是因为不同进程(或线程)获取数据库对象的锁的顺序不同,导致它们相互等待。

ORM 不能让您对锁定获取顺序进行太多控制。您可以修改查询的顺序,但这可能很乏味。特别是当缓存导致其中一些没有命中数据库时。此外,应该在使用相同数据库的任何其他应用程序上以相同的顺序完成。

您可能会检测到死锁错误并执行消息中所说的操作:重试整个过程。使用 NHibernate,这意味着放弃当前会话并重试整个工作单元。

如果您的数据库是 SQL Server,则有一个默认设置会大大增加死锁风险:禁用已提交读快照模式。如果在您的数据库上禁用它,您可以通过启用它来大大降低死锁风险。此模式允许读取已提交隔离级别下的读取停止发出读取锁。

您可以检查此设置

select snapshot_isolation_state_desc, is_read_committed_snapshot_on
    from sys.databases 
    where name = 'YourDbName'

您可以启用此设置

alter database YourDbName
    set allow_snapshot_isolation on

alter database YourDbName
    set read_committed_snapshot on

这要求目标数据库上没有正在运行的事务。当然,这需要数据库的管理员权限。

在我无法更改此设置的应用程序上,我不得不采用更古怪的方式:将 NHibernate 默认隔离模式(connection.isolation配置参数)设置为ReadUncommitted. 我的应用程序主要是只读的,并且我在必须读取然后写入数据的少数事务上显式提升了隔离模式(session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted)通过示例使用)。

您还应该检查所有使用数据库的应用程序当前使用的隔离模式:其中一些使用的隔离级别是否高于实际要求?(RepeatableRead并且Serializable应该尽可能避免。)这是一个耗时的过程,因为它需要很好地理解隔离级别,同时研究每个用例以确定什么是适当的最小隔离级别。

于 2016-03-23T15:03:56.933 回答