因为添加了 @EqualsAndHashCode 注解而导致 User 对象保存时报错的问题

14 篇文章 0 订阅

问题现象

添加了 @EqualsAndHashCode 注解而导致 User 对象保存时报错,堆栈如下:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: vlog.account.User
	at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:279)
	at org.hibernate.type.EntityType.getIdentifier(EntityType.java:495)
	at org.hibernate.type.EntityType.nullSafeSet(EntityType.java:288)
	at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:2102)
	at org.hibernate.loader.Loader.bindParameterValues(Loader.java:2071)
	at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:2006)
	at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1920)
	at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1898)
	at org.hibernate.loader.Loader.doQuery(Loader.java:937)
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340)
	at org.hibernate.loader.Loader.doList(Loader.java:2695)
	at org.hibernate.loader.Loader.doList(Loader.java:2678)
	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2512)
	at org.hibernate.loader.Loader.list(Loader.java:2507)
	at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
	at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1972)
	at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:370)
	at org.grails.orm.hibernate.query.AbstractHibernateQuery.listForCriteria(AbstractHibernateQuery.java:719)
	at org.grails.orm.hibernate.query.AbstractHibernateQuery.list(AbstractHibernateQuery.java:709)
	at org.grails.datastore.gorm.finders.FindAllByFinder.invokeQuery(FindAllByFinder.java:54)
	at org.grails.datastore.gorm.finders.FindAllByFinder$1.doInSession(FindAllByFinder.java:48)
	at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:319)
	at org.grails.datastore.gorm.finders.AbstractFinder.execute(AbstractFinder.java:42)
	at org.grails.datastore.gorm.finders.FindAllByFinder.doInvokeInternal(FindAllByFinder.java:45)
	at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:254)
	at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:392)
	at org.grails.datastore.gorm.finders.FinderMethod$invoke$0.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.grails.datastore.gorm.finders.FinderMethod$invoke$0.call(Unknown Source)
	at org.grails.datastore.gorm.GormStaticApi.methodMissing(GormStaticApi.groovy:185)
	at org.grails.datastore.gorm.GormEntity$Trait$Helper.staticMethodMissing(GormEntity.groovy:777)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
	at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1470)
	at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:985)
	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:180)
	at vlog.account.UserRole.staticMethodMissing(UserRole.groovy)
	at vlog.account.UserRole.$static_methodMissing(UserRole.groovy)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1523)
	at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1511)
	at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:50)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
	at vlog.account.User.getAuthorities(User.groovy:152)
	at vlog.account.User.hashCode(User.groovy)
	at java.util.HashMap.hash(HashMap.java:339)
	at java.util.HashMap.put(HashMap.java:612)
	at java.util.HashSet.add(HashSet.java:220)
	at grails.gorm.validation.PersistentEntityValidator.validate(PersistentEntityValidator.groovy:68)
	at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.save(AbstractHibernateGormInstanceApi.groovy:124)
	at org.grails.datastore.gorm.GormInstanceApi.save(GormInstanceApi.groovy:119)
Disconnected from the target VM, address: '127.0.0.1:3969', transport: 'socket'
	at org.grails.datastore.gorm.GormEntity$Trait$Helper.save(GormEntity.groovy:100)
	at vlog.account.User.save(User.groovy)
	at vlog.account.User.save(User.groovy)
	at org.grails.datastore.gorm.GormEntity$save.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:119)
	at vlog_admin.BootStrap$_createAdminUser_closure3.doCall(BootStrap.groovy:34)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
	at groovy.lang.Closure.call(Closure.java:405)
	at groovy.lang.Closure.call(Closure.java:421)
	at grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
	at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
	at org.grails.datastore.gorm.GormStaticApi.withTransaction(GormStaticApi.groovy:1014)
	at org.grails.datastore.gorm.GormStaticApi.withTransaction(GormStaticApi.groovy:877)
	at org.grails.datastore.gorm.GormEntity$Trait$Helper.withTransaction(GormEntity.groovy:941)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
	at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1470)
	at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:985)
	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:180)
	at vlog.account.User.withTransaction(User.groovy)
	at vlog.account.User$withTransaction.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
	at vlog_admin.BootStrap.createAdminUser(BootStrap.groovy:33)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:351)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:64)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:156)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:160)
	at vlog_admin.BootStrap$_closure1.doCall(BootStrap.groovy:20)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1099)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
	at groovy.lang.Closure.call(Closure.java:405)
	at groovy.lang.Closure.call(Closure.java:399)
	at grails.util.Environment.evaluateEnvironmentSpecificBlock(Environment.java:594)
	at grails.util.Environment.executeForEnvironment(Environment.java:587)
	at grails.util.Environment.executeForCurrentEnvironment(Environment.java:563)
	at org.grails.web.servlet.boostrap.DefaultGrailsBootstrapClass.callInit(DefaultGrailsBootstrapClass.java:74)
	at org.grails.web.servlet.context.GrailsConfigUtils.executeGrailsBootstraps(GrailsConfigUtils.java:83)
	at org.grails.plugins.web.servlet.context.BootStrapClassRunner.onStartup(BootStrapClassRunner.groovy:56)
	at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:269)
	at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:96)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:456)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:443)
	at vlog_admin.Application.main(Application.groovy:11)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

原来是因为给 User 加上了 @EqualsAndHashCode 注解,导致需要读取 authorities 属性,于是会调用 getAuthorities() 方法,而在此方法中会调用 UserRole.findAllByUser(user) 这个方法中需要 user 有 id 值,但本 user 还未保存,是一个暂存态,所以报错了。

解决方法

下面是一个错误的解决方案,因为这会造成死循环。

错误的方案:
当 user 对象还未保存,还没有 id 属性时,getAuthorities() 属性应该返回空集合。代码如下:

class User {
    Set<Role> getAuthorities() {
        if (this.id == null) {
            return Collections.emptySet()
        }else{
            (UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
        }
    }
}

正确的方案,应该是将 authorities 排除在 hashCode 计算之外,更好的方式是用 includes ,只比较 id 字段,否则会导致用 load 方式装载的 domain 对象无法正确地使用 removeFromXXX 方法从关联集合中删除。

@GrailsCompileStatic
@SuppressWarnings("unused")
@EqualsAndHashCode(includes=["id"])
class User {
    Set<Role> getAuthorities() {
      (UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值