2

我引入了一个 TransactionService,我在控制器中使用它来执行乐观事务。它应该

  • 尝试执行给定的事务(=关闭)
  • 如果失败则回滚
  • 如果失败再试一次

它基本上看起来像这样:

class TransactionService {
  transactional = false // Because withTransaction is used below anyway
  def executeOptimisticTransaction(Closure transaction) {
    def success = false
    while (!success) {
      anyDomainClass.withTransaction { status ->
        try {
          transaction()
          success = true
        } catch(Exception e) {
          status.setRollbackOnly()
        }
      }
    }
  }
}

它有点复杂,例如,它在重试之前使用不同的 Thread.sleeps 并在某个阶段中止,但这并不重要。它是从传递事务以作为闭包安全执行的控制器调用的。

我的问题:当服务由于并发更新而遇到 org.hibernate.StaleObjectStateException 时,它会继续重试,但异常永远不会消失。

我已经尝试了不同的方法,例如在控制器传递的事务中重新附加域类,清除服务或控制器中的会话,但没有帮助。我错过了什么?

我应该注意到,当我尝试在使用 status.createSavepoint() 调用 transaction() 之前插入 savePoint 时,我收到一个错误,即“事务管理器不允许嵌套事务”。我尝试了这个,因为我还怀疑存在错误,因为事务是从控制器传递到服务的,并且我需要启动一个新的/嵌套事务来避免它,但是由于错误表明这在我的情况下是不可能的。

或者也许将交易作为闭包传递是问题?

我假设在 .withTransaction 之前使用的域类无关紧要,或者是吗?

4

1 回答 1

1

它本身不是闭包,但我相信transaction里面有一些陈旧的变量引用。如果您尝试只传递在执行时重新读取其对象的闭包怎么办?像

executeOptimisticTransaction {
  Something some = Something.get(id)
  some.properties = aMap
  some.save()
}

我认为如果不在 Hibernate 中重新读取一个对象,就不可能“刷新”它。

是的,你在什么类上调用 .withTransaction() 并不重要。

对于更新计算的总数/评分的示例,这本身就是一个问题的数据重复。我宁愿:

  1. 创建一个(Quartz)作业,该作业将根据一些“脏”标志更新评级 - 这可能会节省一些 DB CPU 以节省更新时间;
  2. 或者在 SQL 或 HQL 中执行,就像Book.executeQuery('update Rating set rating=xxx')使用最新的评级一样。如果您正在针对重负载进行优化,那么您无论如何都不会以 Groovy 方式进行所有操作。不要在 Grails 中保存 Rating 对象,只读取它们。
于 2010-12-07T15:42:48.043 回答