grails什么时候检查Object Staleness?

时间:2015-09-20 23:56:12

标签: grails gorm staleobjectstate

我使用Grails 2.5.1,并且我有一个控制器调用服务方法,偶尔会导致StaleObjectStateException。 service方法中的代码在obj.save()调用周围有一个try catch,它忽略了异常。但是,每当发生其中一个冲突时,日志中仍会显示错误,并且会向客户端返回错误。

我的GameController代码:

def finish(String gameId) {
   def model = [:]
   Game game = gameService.findById(gameId)

   // some other work

   // this line is where the exception points to - NOT a line in GameService:
   model.game = GameSummaryView.fromGame(gameService.scoreGame(game))

   withFormat {
     json {
        render(model as JSON)
     }
   }
}

我的GameService代码:

Game scoreGame(Game game) {
   game.rounds.each { Round round ->
      // some other work
         try {
             scoreRound(round)
             if (round.save()) {
                 updated = true
             }
         } catch (StaleObjectStateException ignore) {
             // ignore and retry
         }
   }
}

堆栈跟踪表示从我的GameController.finish方法生成异常,它并不指向我GameService.scoreGame方法中的任何代码。这对我来说意味着Grails在启动事务时检查过时,而不是在尝试保存/更新对象时?

我多次遇到此异常,通常我会通过不遍历对象图来修复它。

例如,在这种情况下,我删除game.rounds引用并将其替换为:

def rounds = Round.findAllByGameId(game.id)
rounds.each {
   // ....
}

但这意味着在创建交易时不会检查陈旧性,并且它并不总是实用的,在我看来有点挫败了Grails懒惰集合的目的。如果我想自己管理所有的协会,我会。

我已阅读有关Pessimistic and Optimistic Locking的文档,但我的代码遵循那里的示例。

我想更多地了解Grails(GORM)如何/何时检查陈旧性以及在何处处理它?<​​/ p>

1 个答案:

答案 0 :(得分:3)

您不会显示或讨论任何交易配置,但这可能是造成混淆的原因。根据您所看到的内容,我猜您的控制器中有@Transactional个注释。我这样说是因为如果是这种情况,那么事务就会从那里开始,并且(假设您的服务是事务性的)服务方法加入当前事务。

在您致电save()的服务中,但您不会刷新会话。这对于性能更好,特别是如果工作流的另一部分中您进行了其他更改 - 当您可以一次性推送所有更改时,您不希望向每个对象推送两组或更多组更新。由于您没有刷新,并且由于事务未在方法结束时提交,如果控制器尚未启动事务,因此只有在控制器方法完成且事务提交时才会推送更新。 / p>

最好将所有事务(和业务)逻辑移动到服务中,并从控制器中删除每个事务跟踪。除非你愿意接受表演,否则不要急于冲洗“固定”这个。

至于陈旧性检查 - 它相当简单。当Hibernate生成SQL以进行更改时,它的格式为UPDATE tablename SET col1=?, col2=?, ..., colN=? where id=? and version=?。 id显然会匹配,但是如果版本增加了,那么where子句的版本部分将不匹配,JDBC更新计数将为0而不是1,这被解释为意味着其他人在您的阅读和更新数据。