org.hibernate.AssertionFailure: [...] 条目中的空 id(发生异常后不要刷新会话)

Posted

技术标签:

【中文标题】org.hibernate.AssertionFailure: [...] 条目中的空 id(发生异常后不要刷新会话)【英文标题】:org.hibernate.AssertionFailure: null id in [...] entry (don't flush the Session after an exception occurs) 【发布时间】:2016-06-17 01:05:06 【问题描述】:

我使用 jdbc 设置了一个非常基本的 Grails 3 Web 应用程序连接到 PostgreSQL 数据库。您可以在下面找到Cluster 域类和专用服务的代码。

碰巧用相同的slug参数调用了两次createCluster方法:

clusterService.createCluster('Cluster 1', 'cl01')
clusterService.createCluster('Cluster 2', 'cl01')

导致以下异常

错误 org.hibernate.engine.jdbc.spi.SqlExceptionHelper - 错误:重复键值违反唯一约束“uk_9ig73x9wropf95ogrffcvyahk”
  详细信息:键 (slug)=(cl01) 已存在。
[...]
myPackage.Cluster 条目中的空 id(发生异常后不要刷新会话)。堆栈跟踪如下:
    org.hibernate.AssertionFailure: myPackage.Cluster 条目中的空 id(发生异常后不要刷新 Session)
    在 grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93) ~[grails-core-3.1.1.jar:3.1.1]
    在 com.usablenet.utest.AdminController.clusters(AdminController.groovy:28) ~[main/:na]
    在 grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.groovy:53) ~[spring-security-core-3.0.3.jar:na]
    在 grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.groovy:62) ~[spring-security-core-3.0.3.jar:na]
    在 grails.plugin.springsecurity.web.SecurityRequestHolderFilter.doFilter(SecurityRequestHolderFilter.groovy:58) ~[spring-security-core-3.0.3.jar:na]
    在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_60-ea]
    在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_60-ea]
    在 java.lang.Thread.run(Thread.java:745) [na:1.8.0_60-ea]

我认为违反unique 约束的行为会被.validate() 方法拦截,但显然我错了。好的,所以我添加了一个 try/catch 但它基本上没有效果,异常没有被包装,我基本上得到一个 500 内部错误。

我的问题是 2:

    为什么没有像我预期的那样捕获这个异常? null id / don't flush the Session after an exception occurs 错误的真正含义是什么?我没有明确刷新会话,当然新记录的 id 为 null...

在检查了几个指出相同问题的线程后,其中 2 个提示为 Hibernate 正在使用的数据源将 JTA 设置为 TRUE。 说我不知道​​该怎么做,据我了解,JTA 更倾向于管理多个数据库之间的多个事务,所以我肯定会说这不是我的情况......我说的对吗?

Cluster.groovy(域类)

class Cluster 

    String name
    String slug

    static constraints = 
        name    blank: false, unique: true
        slug    blank: false, unique: true
    


ClusterService.groovy

@Transactional
class ClusterService 

    public Cluster createCluster(String name, String slug, boolean flush = false) 
        Cluster cluster = new Cluster(name: name, slug: slug)
        try 
            if(cluster.validate())
                cluster.save(flush: flush)
         catch(Exception e) 
            e.printStackTrace()
        
        return cluster
    

application.yml(数据库配置)

数据源:
    汇集:真
    driverClassName: 'org.postgresql.Driver'
    方言:'org.hibernate.dialect.PostgreSQLDialect'
    用户名:'postgres'
    密码:'postgres'

环境:
    发展:
        数据源:
            dbCreate:创建
            网址:jdbc:postgresql://localhost:5432/myapp

【问题讨论】:

我知道还有其他一些类似的问题,但不幸的是我真的觉得它们不适合我的情况.. 错误未被捕获,因为您捕获了异常并且 Hibernate 正在执行断言,请尝试捕获 ThrowableDon't flush the session 表示所写的确切内容 - 休眠会话不应像您得到的那样在错误之后被刷新 - 或者在会话刷新之前应该丢弃无效对象。 Grails 将在某些点自动刷新会话。如果 unique 工作正常,则不应发生此错误。至于独特,你是对的,它应该被抓住。您使用的是哪个版本的 Grails?你在哪里执行clusterService.createCluster() 方法?你能显示那个代码吗? 感谢您的反馈@droggo! Throwable 不幸的是没有添加任何细节,堆栈跟踪看起来和以前一样。 我使用的是 Grails 3.1.1。对createCluster 的调用在Boostrap.groovy 中执行,但将调用移至控制器,例如clusterService.createCluster(params.name, params.slug) 给出相同的结果。我注意到的另一件事是使clusterService 成为非事务性至少我不再获得500 状态,但堆栈跟踪和异常是相同的,包括true 作为.validate() 方法的“意外”结果与重复的@987654342 @. 如果你能在 Github 上做一个能重现的小项目,我可以提供更多帮助,否则很难说是哪里出了问题 【参考方案1】:

在从头开始构建演示时,我发现问题不在于我的代码,而在于 Grails 应用程序的配置 (build.gradle),只是更改了依赖项

compile "org.grails.plugins:hibernate"

compile "org.grails.plugins:hibernate4"

使问题消失,.validate() 按预期返回false,并且没有抛出错误。

但是我找不到任何关于 Grails 3 之间不兼容性的说明 和 Hibernate 3,如果能找到一个就好了:P

【讨论】:

以上是关于org.hibernate.AssertionFailure: [...] 条目中的空 id(发生异常后不要刷新会话)的主要内容,如果未能解决你的问题,请参考以下文章