org.hibernate.AssertionFailure: null id in [...] entry(发生异常后不刷新Session)
org.hibernate.AssertionFailure: null id in [...] entry (don't flush the Session after an exception occurs)
我使用 jdbc 设置了一个非常基本的 Grails 3 网络应用程序,该应用程序连接到 PostgreSQL 数据库。您可以在下面找到 Cluster
域 class 和专用服务的代码。
碰巧用相同的 slug
参数调用了 createCluster
方法两次:
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 Internal Error.
我的问题是2:
- 为什么这个异常没有像我预期的那样被捕获?
null id / don't flush the Session after an exception occurs
错误的真正含义是什么?我没有明确刷新会话,当然新记录的 id 为空...
在检查了几个指出相同问题的线程后,其中 2 个提示将 Hibernate 使用的数据源设置为 JTA
到 TRUE
。
说我不知道该怎么做,据我了解 JTA 更倾向于管理多个数据库之间的多个事务,所以我肯定会说这不是我的情况......我说得对吗?
Cluster.groovy(域名class)
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(数据库配置)
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
在从头开始构建演示时,我发现问题不在于我的代码,而在于 Grails 应用程序的配置 (build.gradle
),因为仅仅更改了依赖关系
compile "org.grails.plugins:hibernate"
到
compile "org.grails.plugins:hibernate4"
使问题消失,.validate()
按预期返回 false
,并且没有抛出任何错误。
但是我找不到任何关于 Grails 3 之间不兼容的说明
和 Hibernate 3,如果能找到一个就好了 :P
我使用 jdbc 设置了一个非常基本的 Grails 3 网络应用程序,该应用程序连接到 PostgreSQL 数据库。您可以在下面找到 Cluster
域 class 和专用服务的代码。
碰巧用相同的 slug
参数调用了 createCluster
方法两次:
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 Internal Error.
我的问题是2:
- 为什么这个异常没有像我预期的那样被捕获?
null id / don't flush the Session after an exception occurs
错误的真正含义是什么?我没有明确刷新会话,当然新记录的 id 为空...
在检查了几个指出相同问题的线程后,其中 2 个提示将 Hibernate 使用的数据源设置为 JTA
到 TRUE
。
说我不知道该怎么做,据我了解 JTA 更倾向于管理多个数据库之间的多个事务,所以我肯定会说这不是我的情况......我说得对吗?
Cluster.groovy(域名class)
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(数据库配置)
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
在从头开始构建演示时,我发现问题不在于我的代码,而在于 Grails 应用程序的配置 (build.gradle
),因为仅仅更改了依赖关系
compile "org.grails.plugins:hibernate"
到
compile "org.grails.plugins:hibernate4"
使问题消失,.validate()
按预期返回 false
,并且没有抛出任何错误。
但是我找不到任何关于 Grails 3 之间不兼容的说明 和 Hibernate 3,如果能找到一个就好了 :P