Hibernate 尝试锁定域对象时出现StaleObjectStateException
我最近在尝试将子对象添加到父对象的列表时遇到一些并发修改错误 从我所读到的内容来看,添加子对象会影响父对象的版本号,因此,如果另一个线程在我的create方法的中途,它会抱怨 很公平 我返回并尝试锁定域对象,使其在上一次添加完成之前一直处于阻塞状态。令人惊讶的是,当我尝试锁定对象时,它现在似乎抛出了一个StaleObjectStateException 以下是我的测试代码:Hibernate 尝试锁定域对象时出现StaleObjectStateException,hibernate,grails,gorm,Hibernate,Grails,Gorm,我最近在尝试将子对象添加到父对象的列表时遇到一些并发修改错误 从我所读到的内容来看,添加子对象会影响父对象的版本号,因此,如果另一个线程在我的create方法的中途,它会抱怨 很公平 我返回并尝试锁定域对象,使其在上一次添加完成之前一直处于阻塞状态。令人惊讶的是,当我尝试锁定对象时,它现在似乎抛出了一个StaleObjectStateException 以下是我的测试代码: def create(User user, Company company, ReferenceCodeCommand
def create(User user, Company company, ReferenceCodeCommand cmd) {
log.debug("superbooking type: " + cmd.superBooking.getClass().getName())
cmd.superBooking.refresh();
log.debug("#" + random + " Locking superbooking: " + superBooking.id)
def superBooking = SuperBooking.lock(cmd.superBooking.id)
log.debug("#" + random + " Superbooking: " + superBooking.id + " locked")
def referenceCode = new ReferenceCode(cmd.properties)
def random = Math.random()
log.debug("#" + random + " ReferenceCode test point 1. SuperBooking version " + referenceCode.superBooking.version)
superBooking.addToRefs(referenceCode)
log.debug("#" + random + " ReferenceCode test point 2. SuperBooking version " + superBooking.version)
if (!referenceCode.hasErrors()
&& referenceCode.save(flush: true)) {
log.debug("ReferenceCode saved successfully")
} else {
log.warn("#" + random + " ReferenceCode not saved successfully ${referenceCode}.")
}
log.debug("#" + random + " ReferenceCode test point 3. SuperBooking version " + superBooking.version)
superBooking.save(flush: true, failOnError: true)
log.debug("#" + random + " ReferenceCode test point 4. SuperBooking version " + superBooking.version)
return referenceCode
}
下面是一些示例输出:
2013-09-06 13:31:21,645 [http-bio-8080-exec-19] DEBUG dao.ReferenceCodeDAOService - superbooking type: com.ngs.id.model.SuperBooking
2013-09-06 13:31:21,667 [http-bio-8080-exec-19] DEBUG dao.ReferenceCodeDAOService - #0.06947409938388194 Locking superbooking: 208535
2013-09-06 13:31:21,667 [http-bio-8080-exec-19] DEBUG dao.ReferenceCodeDAOService - #0.06947409938388194 Superbooking: 208535 locked
2013-09-06 13:31:21,667 [http-bio-8080-exec-19] DEBUG dao.ReferenceCodeDAOService - #0.06947409938388194 ReferenceCode test point 1. SuperBooking version 6
2013-09-06 13:31:21,667 [http-bio-8080-exec-19] DEBUG dao.ReferenceCodeDAOService - #0.06947409938388194 ReferenceCode test point 2. SuperBooking version 6
2013-09-06 13:31:21,701 [http-bio-8080-exec-19] DEBUG dao.ReferenceCodeDAOService - #0.06947409938388194 ReferenceCode test point 3. SuperBooking version 7
2013-09-06 13:31:21,708 [http-bio-8080-exec-19] DEBUG dao.ReferenceCodeDAOService - #0.06947409938388194 ReferenceCode test point 4. SuperBooking version 7
| Error 2013-09-06 13:31:21,715 [http-bio-8080-exec-20] ERROR errors.GrailsExceptionResolver - StaleObjectStateException occurred when processing request: [POST] /interpreter-direct/api/superBooking/208535/referenceCode/
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.ngs.id.model.SuperBooking#208535]. Stacktrace follows:
Message: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.ngs.id.model.SuperBooking#208535]
错误发生在我锁定超级预订的线路上。这让我很困惑:根据我所读的内容,lock()将从数据库中获取行并将其锁定,直到事务完成。我本以为StaleObjectStateException在这里根本没有意义
有没有人能给我一些建议,或者其他的方法?这对我们的应用程序有严重影响
谢谢 我想您使用db锁定是为了支持可以使用同一个db的多个服务器。 看起来你的代码很好。导致此异常的原因是在调试时运行并在没有正确完成执行的情况下停止,因此不会提交db事务并保留锁。 当没有为同一cmd.superBooking.id打开任何事务时,尝试执行此操作。或者在测试时尝试使用不同的ID。
通常,如果您的应用程序更有可能不会在同一行上执行多个更新,请改用乐观锁定。也就是说,不要使用lock方法,而是对StaleObjectException使用try-and-catch。谢谢Tal,不幸的是,我知道javascript前端经常会突发发送更新,这会导致并发问题。当我第一次开始处理这个问题时,事务是关闭的,所以这没有帮助。