简体   繁体   English

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

[英]Grails and hibernate session, save to database on exception

I'm using Grails framework. 我正在使用Grails框架。

Want to save something to database on failure (after RuntimeException is thrown). 想要在失败时将某些内容保存到数据库中(引发RuntimeException之后)。 Let's say I have something like this in one of transactional services: 假设我在一种事务服务中有这样的东西:

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

Current version will fail because session is set to rollback. 当前版本将失败,因为会话设置为回滚。

I tried to solve this problem in multiple ways and what I found so far is: 我试图以多种方式解决此问题,到目前为止,我发现的是:

.withTransaction - will not work because will bind transaction to current session .withTransaction无效,因为它将事务绑定到当前会话

.withSession - will not work because will just reuse existing session .withSession将不起作用,因为它将仅重用现有会话

.withNewSession - alone will not work because it will create new session in same thread (same thread = same db connection, so it will fail with SQL exception) .withNewSession单独将不起作用,因为它将在同一线程中创建新会话(同一线程=相同的数据库连接,因此它将因SQL异常而失败)

The only working solution I found so far is to create new thread and new hibernate session. 到目前为止,我发现的唯一可行的解​​决方案是创建新线程和新的休眠会话。 Is it really the only (and the right) way to accomplish this? 这真的是唯一(正确的)方法吗?

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()
}

Usage: 用法:

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

I think your solution is better but I thought of giving you this suggestion anyway: call new FatalErrorDomainObject().save() in a separate transaction before the rest of your logic and at the end of it, before the commit, delete the FatalErrorDomainObject. 我认为您的解决方案更好,但是我仍然想给您这个建议:在其余逻辑之前在单独的事务中调用new FatalErrorDomainObject().save() ,并在提交结束之前在逻辑末尾删除FatalErrorDomainObject。 Something like this: 像这样:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM