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

时间:2016-03-03 15:46:40

标签: hibernate postgresql grails gorm grails-domain-class

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

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

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

导致以下异常

ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ERROR: duplicate key value violates unique constraint "uk_9ig73x9wropf95ogrffcvyahk"
  Detail: Key (slug)=(cl01) already exists.
[...]
null id in myPackage.Cluster entry (don't flush the Session after an exception occurs). Stacktrace follows:
    org.hibernate.AssertionFailure: null id in myPackage.Cluster entry (don't flush the Session after an exception occurs)
    at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93) ~[grails-core-3.1.1.jar:3.1.1]
    at com.usablenet.utest.AdminController.clusters(AdminController.groovy:28) ~[main/:na]
    at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.groovy:53) ~[spring-security-core-3.0.3.jar:na]
    at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.groovy:62) ~[spring-security-core-3.0.3.jar:na]
    at grails.plugin.springsecurity.web.SecurityRequestHolderFilter.doFilter(SecurityRequestHolderFilter.groovy:58) ~[spring-security-core-3.0.3.jar:na]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_60-ea]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_60-ea]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60-ea]

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

我的问题是2:

  1. 为什么这个例外没有像我期望的那样被捕获?
  2. null id / don't flush the Session after an exception occurs错误究竟意味着什么?我没有明确地刷新会话,当然新记录的id是空的......
  3. 在检查指出同一问题的几个线程后,其中2个暗示将JTA设置为TRUE以获取Hibernate正在使用的数据源。 说我不知道​​如何做到这一点,据我所知,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 (db配置)

    dataSource:
        pooled: true
        driverClassName: 'org.postgresql.Driver'
        dialect: 'org.hibernate.dialect.PostgreSQLDialect'
        username: 'postgres'
        password: 'postgres'
    
    environments:
        development:
            dataSource:
                dbCreate: create
                url: jdbc:postgresql://localhost:5432/myapp

1 个答案:

答案 0 :(得分:0)

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

compile "org.grails.plugins:hibernate"

compile "org.grails.plugins:hibernate4"

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

但是我找不到任何有关Grails 3之间不兼容性的说明 和Hibernate 3一样,找到一个很好:P