代码之家  ›  专栏  ›  技术社区  ›  mark

如何用NHibernate设置正确的事务隔离模式?

  •  2
  • mark  · 技术社区  · 14 年前

    我们已经从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>
    

    我相信外面有个好心人,他知道答案 我的问题。请,请,请分享你的智慧。。。

    谢谢。

    2 回复  |  直到 14 年前
        1
  •  7
  •   James Kovacs    14 年前

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

    <property name=“connection.isolation”>已提交</属性>

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

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

    你必须检查FireBird文档,看看它支持哪些文档。

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

        2
  •  2
  •   Diego Mijelshon    14 年前

    除了James解释的默认隔离级别之外,还可以使用 ISession.BeginTransaction 这需要一个 IsolationLevel .