Grails/Hibernate: исключение Null Pointer при версировании

Работа с устаревшей кодовой базой в 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)

Ответы

Ответ 1

Вот мое понимание трассы:

  • вы или что-то делаете findBy
  • этот триггеры a 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
}

Кажется очевидным, что version, переданный в increment, равен null.

Таким образом, я бы посмотрел в базе данных запись со значением null в ее столбце версии. Активация регистрации SQL может помочь сузить поиск.

Ответ 2

У меня была та же проблема. Это проблема со старыми записями базы данных. Вы добавили столбец версии в таблицу базы данных и аннотацию @Version в своем VO, и она отлично работает для новых объектов, созданных после этого chagne, однако для старых объектов это не работает - значение в этом столбце равно null. Решение состоит в том, чтобы обновить все старые объекты - их столбец версии с 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"