我最近在尝试将子对象添加到父对象的列表时遇到了一些并发修改错误。
根据我的阅读,添加子对象将会破坏父对象的版本号,因此如果另一个线程在我的create方法的中途,它会抱怨。
足够公平。
我回去试图锁定域对象,因此它会阻塞,直到上一次添加完成。令人惊讶的是,当我尝试锁定对象时,它现在似乎抛出StaleObjectStateException!
这是我的测试代码:
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]
错误发生在我锁定SuperBooking的行上。这对我来说真的很混乱:从我所读到的,lock()将从数据库中获取行并锁定它直到事务完成。我原以为StaleObjectStateException在这里甚至没有意义。
有没有人对我有任何提示,或者可能是替代方法?这对我们的申请产生了严重影响。
谢谢!
答案 0 :(得分:0)
我认为您使用数据库锁定以支持可以使用相同数据库的多服务器。 看起来你的代码很好。导致此异常的原因是运行调试并在没有正确完成执行的情况下停止执行,因此db事务未提交且锁定仍然存在。 当没有为同一cmd.superBooking.id打开任何事务时,尝试执行此操作。或者在测试时尝试使用不同的ID。 通常,如果您的应用程序更有可能不在同一行上执行多次更新,请改用乐观锁定。即而不是使用lock方法,使用try和catch来获取StaleObjectException。