【问题标题】:Grails/Hibernate: Null Pointer Exception on versioningGrails/Hibernate:版本控制上的空指针异常
【发布时间】:2011-04-10 12:07:38
【问题描述】:

在 Grails 中使用遗留代码库。在某些情况下(我们不清楚具体是什么),我们会得到一个神秘的 NPE,堆栈跟踪如下,同时执行 findBy。

到目前为止,我们有点受阻;这出现在 Hibernate 的几个论坛中,但响应似乎归结为“您的架构有问题”。如果能找到一些额外的细节来帮助我们追踪问题,那就太好了。

更新

感谢您的回答。是的,很明显,在这个 NPE 发生时,versionnull。麻烦的是,当我们在代码中查看时,它不是 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.

标签: hibernate orm grails


【解决方案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
    }
    

    很明显,传递给incrementversionnull

    因此,我将在数据库中查找其版本列中具有NULL 值的记录。激活 SQL 日志记录可能有助于缩小搜索范围。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      • 1970-01-01
      • 1970-01-01
      • 2015-06-24
      • 2012-06-05
      • 1970-01-01
      • 2013-03-22
      相关资源
      最近更新 更多