NHibernate IStatelessSession CreateQuery失败

时间:2016-03-23 07:19:30

标签: c# nhibernate transactions execute createquery

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

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."}

1 个答案:

答案 0 :(得分:1)

解决死锁可能很困难,特别是在使用ORM时。通常会发生死锁,因为不同进程(或线程)不会以相同的顺序获取数据库对象上的锁,导致它们彼此等待。

ORM不会对锁定获取顺序给予太多控制。您可以修改您的查询订单,但这可能是乏味的。特别是当缓存导致其中一些不能命中DB时。此外,它应该使用相同的数据库在任何其他应用程序上使用相同的顺序。

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

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

您可以使用

检查此设置
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

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

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

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