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"