简而言之,我正在尝试解决的是如何使用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"
}
}
}
一旦发生错误,我似乎无法清除hibernate会话。在每个后续记录更新时,我收到错误:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction
表示原始失败的域名。
修订:
瓦希德,谢谢你的建议。我试过了。我意识到一个问题是我跨越事务边界传递对象。所以我尝试使用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仍然失败,即使我没有调用它上面的保存。很奇怪......
答案 0 :(得分:0)
一种简单的方法是循环然后使用validate()。如果确实失败了,那么只需存储失败实体的id并继续。
if(!domainObject.validate()){
// store Id for trying it again later ?
}else{
// Save
}