我最近在尝试将子对象添加到父对象的列表时遇到了一些并发修改错误。
根据我的阅读,添加子对象会影响父对象的版本号,因此如果另一个线程在我的 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 在这里甚至没有意义。
有没有人对我有任何提示,或者可能是另一种方法?这对我们的应用程序产生了严重影响。
谢谢!