exception - 如何在事务中从 Grails 中的数据库错误中恢复

简而言之,我要解决的是如何使用 Hibernate 从 Grails 应用程序中的某些数据库错误中恢复,并继续处理跳过作为一批更改一部分的失败行更新的事务。

该应用程序使用 Grails 2.3.11,但我也尝试使用 1.3.8 版本,但结果类似。

基本上有一个 Grails 服务类,它遍历导入记录的列表并尝试适本地更新关联的主记录。在某些情况下,domain.save(flush:true) 期间可能会发生异常。打电话,例如org.hibernate.exception.DataException由于诸如(数据截断:列的数据太长......)等问题而引发。

在这一点上,我已经尝试过:

  • 禁用事务
  • 对每条记录使用 domainObj.withTransaction()
  • 尝试各种@Transactional 注释
  • 捕获异常后调用 domain.clearErrors() 和 domain.discard()
  • 尝试使用带有事务注释和 noRollbackFor 的嵌套服务,如下所示
  • 许多其他方法,但我没有尝试过

  • 示例代码:
    @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
    }
    

    https://stackoverflow.com/questions/29438818/

    相关文章:

    grails - Grails:如何从BuildConfig.groovy中知道正在执行哪个命令

    ssh - 如何从第二台机器访问 Github 存储库?

    mongodb - 在grails和MongoDB插件的条件查询中使用allowDiskUse?

    grails - “grails -Dserver.port=9999 run-app”无效

    grails - 使用插件时如何在Grails中添加Quartz监听器

    php - 通过php我如何关闭由php ssh2_connect创建的事件ssh连接?

    security - 在 Groovy 动态 SQL 中检测 SQL 注入(inject)

    ruby-on-rails-3 - 使用 Heroku 访问和部署问题

    macos - 假设我知道root密码,如何在OS X中使用标准帐户制作一个sudo本身的Bash脚

    ssh - 将现有的 ssh_authorized_keys 导入 puppet 资源