简而言之,我正在尝试解决的问题是如何使用Hibernate从Grails应用程序中的某些数据库错误中恢复并继续跳过跳过作为一批更改一部分的失败行更新的事务。
该应用程序使用Grails 2.3.11,但我也尝试使用1.3.8版本,但结果类似。
基本上,有一个Grails服务类,它对导入的记录列表进行迭代,并尝试适当地更新关联的主记录。在某些情况下,domain.save(flush:true)
调用期间可能会发生异常,例如由于诸如(数据截断:数据对于列而言太长...)之类的问题而引发了org.hibernate.exception.DataException
。
在这一点上,我已经尝试过:
示例代码:
@Transactional
class UpdateService {
public updateBatch(Integer batchId) {
...
list.each { record ->
record.value = 123
try {
nestedService.saveDomain()
} catch (e) {
record.clearErrors()
record.discard()
}
}
batch.status = "POSTED"
batch.save()
}
}
@Transactional
class NestedService {
@Transactional(propagation = Propagation.REQUIRED, noRollbackFor = RuntimeException.class)
public void saveDomain(domainObj) throws RuntimeException {
if (domainObj.validate() && domainObj.save(flush:true) {
log.info "domain $domain was saved"
}
}
}
一旦发生错误,我似乎无法清除休眠 session 。在每个后续记录被更新时,我收到错误:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction
它指示原始失败的域ID。
修订版:
瓦希德,谢谢你的建议。我已经尝试过了。我意识到一个问题是我正在跨事务边界传递对象。因此,我对NestedService类进行了试验,其工作大致如下:
@Transactional(propagation = Propagation.REQUIRE_NEW)
public void saveDomain(domainObj) {
def newObj = new Domain.get(domainObj.id)
newObj.properties = domainObj.properties
if (newObj.validate() && newObj.save(force:true) ) { ... }
我希望它能正常工作,但是即使我没有在其上调用保存,原始的domainObj仍然会失败。很奇怪...
最佳答案
一种简单的方法是循环然后使用validate()。如果确实失败,则只需存储失败实体的ID并继续。
if(!domainObject.validate()){
// store Id for trying it again later ?
}else{
// Save
}
关于exception - 如何从事务中的Grails中的数据库错误中恢复,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29438818/