Grails afterInsert钩子问题与Hibernate 5.1和PostgreSQL

时间:2017-03-24 11:30:46

标签: postgresql hibernate grails

在最近升级到Hibernate 5.1的现有Grails 3.1.15应用程序中,开始出现afterInsert(或其他)钩子的奇怪问题。经过几个小时的测试,我可以追溯到Hibernate 5.1 + PostgreSQL组合 - 问题与H2无法重现。要重现,请创建一个由2个域对象组成的简单应用程序 - 审计跟踪和用户,如下所示:

class Audit {
    Date dateCreated
    String auditData
}

class User {
    String name
    String email

    def afterInsert() {
        new Audit(auditData: "User created: $this").save()
    }
}

上面的代码适用于Hibernate 4,但是,如果应用程序升级到Hibernate5插件+ Hibernate 5.1.x(使用5.1.0.Final和5.1.5.Final测试),上述场景将始终导致尝试保存新的User实例时出现ConcurrentModificationException。您可以使用脚手架控制器来重现。请注意,这只发生在PostgreSQL作为数据源的情况下 - 使用H2它仍然可以正常工作。

现在,根据GORM Docs(参见第8.1.3章),当尝试在beforeUpdate或afterInsert挂钩中保存其他对象时,应该使用新会话:

def afterInsert() {
    Audit.withNewSession() {
        new Audit(auditData: "User created: $this").save()
        /* no exception logged, but Audit instance not preserved */
    }
}

但这并不能真正解决PSQL的问题。异常消失,User实例保持不变,但Audit实例未保存。同样,这段代码可以和H2一起使用。要真正避免PSQL的问题,您必须在afterInsert中手动刷新会话:

def afterInsert() {
    Audit.withNewSession() { session ->
        new Audit(auditData: "User created: $this").save()
        session.flush() 
        /* finally no exceptions, both User and Audit saved */
    }
}

问题:这是一个错误,还是这个预期?我觉得有点怀疑需要手动刷新才能保持Audit实例 - 当我看到它没有与H2冲洗并且似乎只影响PostgreSQL时更是如此。但我无法找到任何报告 - 任何指针都会受到赞赏!

为了完整起见,我使用PostgreSQL的以下JDBC驱动程序版本进行了测试:

runtime 'org.postgresql:postgresql:9.3-1101-jdbc41'
runtime 'org.postgresql:postgresql:9.4.1208.jre7'
runtime 'org.postgresql:postgresql:42.0.0'

对于升级到Hibernate 5.1,使用了以下依赖项:

classpath "org.grails.plugins:hibernate5:5.0.13"
...
compile "org.grails.plugins:hibernate5:5.0.13"
compile "org.hibernate:hibernate-core:5.1.5.Final"
compile "org.hibernate:hibernate-ehcache:5.1.5.Final"

0 个答案:

没有答案