【问题标题】:Setting the right transaction isolation mode with NHibernate, how to?使用 NHibernate 设置正确的事务隔离模式,如何?
【发布时间】:2010-11-09 02:35:37
【问题描述】:

我们已经从 sqlite 切换到 FireBird 嵌入式服务器,因为 FB 似乎支持数据库的并发更新,但我们有时 有这些异常来自它:

2010-10-28 15:49:31,242 [56] ERROR NetworkCatcher.Entities.Agent.Server.RunResultManager - Failed to send result to server 32W2K3SP2VM-DEV. NHibernate.Exceptions.GenericADOException: could not update: ExecutionEntry#89_19_32W2K3SP2VM-DEV][SQL: UPDATE Run SET ExecutionId = ?, Source = ?, Destination = ?, ProtocolId = ?, Duration = ?, SampleCount = ?, StartTime = ?, ServerHostName = ?, SamplesSentToServer = ?, SampleInterval = ?, Parameters = ? WHERE Id = ?] ---> FirebirdSql.Data.FirebirdClient.FbException: deadlock
update conflicts with concurrent update
concurrent transaction number is 31632 --->
FirebirdSql.Data.Common.IscException: deadlock
update conflicts with concurrent update
concurrent transaction number is 31632
   at FirebirdSql.Data.Client.Native.FesDatabase.ParseStatusVector(IntPtr[]
statusVector)
   at FirebirdSql.Data.Client.Native.FesStatement.Execute()
   at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteCommand(CommandBehavior
behavior, Boolean returnsSet)
   at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteCommand(CommandBehavior
behavior)
   at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteNonQuery()
.
.
.

FB 对此的回应是 “为什么你认为这是一个错误?这是定期更新冲突导致 通过两个事务同时更新同一记录。什么是 你的事务隔离模式?”

这句话让我困惑了两次——一次,因为我不愉快 惊讶地发现我可以同时写相同的记录 第二次——我不知道什么是我的 事务隔离模式以及如何使用它来序列化写入 相同的记录。

正在更新的对象的映射是:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-
import="true">
  <class name="NetworkCatcher.Entities.Agent.Server.ExecutionManager+ExecutionEntry,NC.Entities.Agent.Server" lazy="false" table="Run" entity-name="ExecutionEntry">
    <id name="Id" column="Id" type="string" >
      <generator class="assigned"/>
    </id>
    <property name="ExecutionId"/>
    <property name="Source"/>
    <property name="Destination"/>
    <property name="ProtocolId" type="string"/>
    <property name="Duration"/>
    <property name="SampleCount"/>
    <property name="StartTime"/>
    <property name="ServerHostName"/>
    <property name="m_samplesSentToServer" column="SamplesSentToServer" type="int" access="field" />
    <property name="SampleInterval"/>
    <property name="Parameters" type="binary"/>
  </class>
</hibernate-mapping>

我相信那里有一个好心人,谁知道答案 我的问题。请,请,请分享你的智慧......

谢谢。

【问题讨论】:

    标签: database nhibernate


    【解决方案1】:

    事务隔离模式通常在你的 hibernatem.cfg.xml 文件中设置:

    ReadCommitted

    http://www.nhforge.org/doc/nh/en/index.html#configuration-hibernatejdbc

    您可以在 System.Data.IsolationLevel 的 MSDN 文档中找到每个有效值和描述的列表:

    http://msdn.microsoft.com/en-us/library/system.data.isolationlevel.aspx

    您必须查看 FireBird 文档以了解它支持哪些文档。

    关于您的异常,您在更新记录时遇到了死锁,这在关系数据库中是预期的。您应该准备好捕获死锁异常并重试该操作。这与 NHibernate 无关,与关系数据库如何支持事务有关。基本上,您遇到了一种情况,您尝试在两个不同的事务中更新相同的两条记录 A 和 B。一个事务在 A 上具有锁,而另一个事务在 B 上具有锁。每个事务都需要另一个记录上的锁才能完成。数据库引擎选择死锁牺牲品,回滚其事务,向其抛出死锁异常,并允许其他事务完成。如果它不这样做,两个事务将永远等待(或事务超时)以等待另一个事务完成。 (这可能是一个更复杂的记录循环、r1..rN 和多个事务,但同样的想法也适用。)最终结果是,作为应用程序开发人员,您必须准备好重试导致死锁的操作,无论您使用的是 NHibernate、原始 ADO.NET 还是任何其他利用关系数据库的技术。

    【讨论】:

      【解决方案2】:

      除了 James 解释的默认隔离级别之外,您还可以使用 ISession.BeginTransaction 的重载来设置单个事务的隔离级别,该重载采用 IsolationLevel

      请注意,这不仅仅是 NH 的事情:它是一个标准的 ADO.NET 概念,因此您可以在 MSDN 中阅读有关它的更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多