Grails/Hibernate:版本控制上的空指针异常
Posted
技术标签:
【中文标题】Grails/Hibernate:版本控制上的空指针异常【英文标题】:Grails/Hibernate: Null Pointer Exception on versioning 【发布时间】:2011-04-10 12:07:38 【问题描述】:在 Grails 中使用遗留代码库。在某些情况下(我们不清楚具体是什么),我们会得到一个神秘的 NPE,堆栈跟踪如下,同时执行 findBy。
到目前为止,我们有点受阻;这出现在 Hibernate 的几个论坛中,但响应似乎归结为“您的架构有问题”。如果能找到一些额外的细节来帮助我们追踪问题,那就太好了。
更新
感谢您的回答。是的,很明显,在这个 NPE 发生时,version
是 null
。麻烦的是,当我们在代码中查看时,它不是 null
。
我们开始怀疑存在线程问题。
Caused by: java.lang.NullPointerException
at org.hibernate.type.LongType.next(LongType.java:79)
at org.hibernate.engine.Versioning.increment(Versioning.java:131)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getNextVersion(DefaultFlushEntityEventListener.java:387)
at org.hibernate.event.def.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:279)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:151)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:49)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.codehaus.groovy.grails.plugins.quartz.listeners.SessionBinderJobListener.jobWasExecuted(SessionBinderJobListener.java:58)
at org.quartz.core.QuartzScheduler.notifyJobListenersWasExecuted(QuartzScheduler.java:1910)
【问题讨论】:
当然,我不知道所有的细节,但是......线程问题怎么能抵消一些东西?完全排除具有空版本列的记录? 哦,不,正好相反:很明显,此时版本列 为 为空。很难弄清楚 why 因为在周围的代码中它似乎不是。不过,我们对线程问题有一些确认,因为我们将其强制为单线程并停止获取 NPE。仍然不明白根本原因,'tho. 【参考方案1】:@Version
@Column(name = "xxx")
private Integer xxx;
在你的VO中找到@Version注解,并在数据库中将此列设置为默认值;
【讨论】:
事实证明(已经很久了)这实际上是一个并发问题,两个线程在处理同一个条目。【参考方案2】:我遇到了同样的问题。这是旧数据库记录的问题。您已经在数据库表中添加了版本列,并在 VO 中添加了 @Version 注释,它适用于在该 chagne 之后创建的新对象,但是它对于旧对象失败 - 此列中的值为 null。解决方案是更新所有旧对象 - 它们的版本列为 0(或某些不同的值,具体取决于数据类型)。希望对你有帮助。
【讨论】:
这对我有用。我为已经存在的对象添加了@Version,我必须全部更新它们并设置版本= 0。现在工作正常。【参考方案3】:<version name="versionID" type="java.lang.Long" unsaved-value="null">
<column name="version" precision="10" scale="0"/>
</version>
尝试删除 unsaved-value="null" 或添加 unsved-value="null"
【讨论】:
【参考方案4】:这是我对trace的理解:
你或某事做一个findBy
这个triggers一个flush
会话包含一个脏对象,其版本字段(Long
类型)需要更新
Hibernate 尝试获取版本字段的下一个值以进行更新
这就是您获得 NPE 的地方
org.hibernate.engine.Versioning.increment(Versioning.java:131)
的正文是:
public static Object increment(Object version, VersionType versionType, SessionImplementor session)
Object next = versionType.next( version, session ); // line 131
if ( log.isTraceEnabled() )
log.trace(
"Incrementing: " +
versionType.toLoggableString( version, session.getFactory() ) +
" to " +
versionType.toLoggableString( next, session.getFactory() )
);
return next;
以及org.hibernate.type.LongType.next(LongType.java:79)
的主体(提供了上面versionType.next
的实现):
public Object next(Object current, SessionImplementor session)
return new Long( ( (Long) current ).longValue() + 1 ); // line 79
很明显,传递给increment
的version
是null
。
因此,我将在数据库中查找其版本列中具有NULL
值的记录。激活 SQL 日志记录可能有助于缩小搜索范围。
【讨论】:
以上是关于Grails/Hibernate:版本控制上的空指针异常的主要内容,如果未能解决你的问题,请参考以下文章
grails - org.hibernate.QueryException(无法解析属性)
Grails (Hibernate) java.time.ZoneId 到数据库的映射
Grails/Hibernate 数据库在负载下崩溃:无法连接(即使在池中)
Grails hibernate/Searchable 通过给出以下异常来停止服务器启动