2016-03-23 16 views
0

当我们在上个星期五发布时,我收到了一个我没有接受的错误。该错误信息是:NHibernate IStatelessSession 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."}

+2

首先,显示完整的异常堆栈..上面的那部分将只是一个开始...真实和有趣的信息将遵循... –

+1

正如Radim所指出的,您的错误信息不足。它只是告诉它不能做什么。通常它有一些原因。记录异常的详细信息,包括其“InnerException”。如果您没有更多,请添加log4net,将其配置为至少记录警告和更高级别,然后NHibernate应该发布关于失败的详细日志。 –

+0

好的谢谢。我希望这是一些典型的错误或什么。调试很难,因为我必须遵循一个发布计划(我可以每个月发布一次),因此只能接受测试。所以即使添加log4net,我也要等一个月才能看到错误。 – Tjab

回答

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)。这是一个耗时的过程,因为它需要很好地理解隔离级别,同时研究每个用例以确定什么是适当的最小隔离级别。

+0

谢谢你非常详细的答案!提交的快照隔离/读取确实设置为false/0,并且我不知道这个设置。 – Tjab

+1

我忘记了关于读取提交快照模式的一点:它会导致更多的tempdb空间使用。你的DBA应该知道它。 –

+0

嗯,那我也需要注意这一点。数据库本身非常庞大,目前在1个表中谈论将近4亿条记录...不知道它是'表/ db越大,tempdb空间使用得越多',但如果是这样的话。 :) – Tjab

相关问题