NHibernate session.flush()失败但进行了更改

时间:2009-12-05 16:09:47

标签: sql-server nhibernate hibernate

我们有一个SQL Server数据库表,其中包含用户ID,某些数值,例如余额和版本列。

我们有多个线程并行更新此表的值列,每个线程都在自己的事务和会话中(我们使用的是每线程会话模型)。由于我们希望发生所有逻辑事务,因此每个线程都会执行以下操作:

  1. 加载当前行(映射到某个类型)。
  2. 根据旧值更改值。 (例如加50)。
  3. 了Session.update(OBJ)
  4. session.flush()(因为我们很乐观,我们希望确保在更新之前我们有正确的版本值)
  5. 如果第4步(flush)抛出StaleStateException,则刷新对象(使用lockmode.read)并转到步骤1
  6. 我们每个逻辑事务只执行一定次数,如果我们在X次尝试后无法提交,我们拒绝逻辑事务。

    每个这样的线程周期性地提交,例如在100次成功的逻辑事务之后,将提交引发的I / O保持在可管理的级别。意思是 - 我们有一个具有多个刷新的单个数据库事务(每个事务),每次逻辑更改至少一次。

    你问这里有什么问题?好吧,在提交时,我们看到对失败的逻辑对象的更改。 具体来说,如果我们通过步骤1(第一次)时值为50,并且我们尝试将其更新为100(但是我们失败了,因为例如另一个线程将其更改为70),则提交值50这一行。显然这是不正确的。

    我们在这里缺少什么?

4 个答案:

答案 0 :(得分:2)

好吧,我在这里没有太多的经验,但有一点我记得读in the documentation是因为如果发生异常,你应该立即回滚事务并处理会话。也许您的问题与会话处于不一致状态有关?

此外,在此处调用代码中的更新为not necessary。由于您在该会话中加载了该对象,因此它已被nhibernate跟踪。

答案 1 :(得分:1)

如果您想进行更改,为什么还要打扰行版本?如果你只是总是更新数据并让最后一笔交易获胜,那听起来你应该得到相同的结果。

至于更新成为永久更新的原因,它取决于版本检查/更新的SQL语句和事务控制的内容,这是您从代码示例中省略的。如果打开Hibernate SQL日志记录,很可能会发生这种情况。

答案 2 :(得分:0)

我不是一个nhibernate大师,但回答似乎很简单。

当nhibernate加载一个对象时,只要它在nhibernate会话缓存中就不希望它在db中改变。

如你所说 - 你有多线程应用程序。

这就是发生的事情=>

  • 第一个线程加载一个实体
  • 第二个线程加载一个实体
  • 第一个线程更改实体
  • 第二个主题更改实体 =>发现加载的实体已被其他东西改变,并担心它已经搞砸了第一个线程所做的更改 - 抛出异常让程序员意识到这一点。

您缺少锁定机制。不能说明如何正确和优雅地应用它。也许Transaction会有所帮助。

当我们同时使用nhibernate和raw ado.net时,我们遇到了类似的问题(幸运的是 - 仅用于查询 - 至少对于生产代码而言)。我们所要做的就是 - 在插入/更新时强制更新db,这样我们就可以通过全文搜索查询某些特定实体。

当我们使用原始ado.net重置db时,在集成测试中有StaleStateException。 NHibernate会话通过大量测试活跃起来,但每次测试都试图在不了解NHibernate的情况下清理db。

答案 3 :(得分:0)