Grails和hibernate会话,异常时保存到数据库

Grails和hibernate会话,异常时保存到数据库,hibernate,session,exception,grails,transactions,Hibernate,Session,Exception,Grails,Transactions,我正在使用Grails框架 要在引发RuntimeException后失败时将某些内容保存到数据库。假设我在一个事务性服务中有这样的功能: try { throw new RuntimeException() } catch(Exception ex) { new FatalErrorDomainObject().save() } 当前版本将失败,因为会话设置为回滚 我尝试用多种方法解决这个问题,目前为止我发现: .withTransaction-将不工作,因为它将事务绑定到当前会

我正在使用Grails框架

要在引发RuntimeException后失败时将某些内容保存到数据库。假设我在一个事务性服务中有这样的功能:

try {
   throw new RuntimeException()
} catch(Exception ex) {
   new FatalErrorDomainObject().save()
}
当前版本将失败,因为会话设置为回滚

我尝试用多种方法解决这个问题,目前为止我发现:

.withTransaction-将不工作,因为它将事务绑定到当前会话

.withSession-将不起作用,因为它将只重用现有会话

.withNewSession-单独使用将不起作用,因为它将在同一线程中创建新会话同一线程=同一数据库连接,因此它将失败并出现SQL异常

到目前为止,我找到的唯一可行的解决方案是创建新的线程和新的hibernate会话。这真的是实现这一目标的唯一正确途径吗

public static void syncSession(Closure job) {
    // Checking environment in production code it's not very elegant but thanks to this it's transparent
    // for all tests and makes them DRY.
    if(Environment.current == Environment.TEST) {
        job.call()
    }
    Thread t = new Thread({
        DomainObject.withNewSession {
            job.call()
        }
    })
    t.start()
    t.join()
}
用法:

try {
   throw new RuntimeException()
} catch(Exception ex) {
   syncSession {
      new FatalErrorDomainObject().save()
   }
}

我认为您的解决方案更好,但我还是想给您一个建议:在剩下的逻辑之前调用new FatalErrorDomainObject.save在一个单独的事务中,在事务结束时,在提交之前,删除FatalErrorDomainObject。大概是这样的:

def fatalError = new FatalErrorDomainObject()
FatalErrorDomainObject.withTransaction { status ->
    fatalError.save()
}
doSomethingThatMightThrowRuntimeException()
FatalErrorDomainObject.get(fatalError.id).delete()

这个错误对象用于通知发生了错误,它会标记所有调用都是错误的,例如,通过电子邮件传播错误,然后我会默默地删除它。在我的情况下不起作用,但谢谢你的建议。