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 正在执行断言,请尝试捕获Throwable
。 Don'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(发生异常后不要刷新会话)的主要内容,如果未能解决你的问题,请参考以下文章