Hibernate-reactive: Пример не работает с ORM 5.4.24

Созданный на 20 нояб. 2020  ·  37Комментарии  ·  Источник: hibernate/hibernate-reactive

Пример одного из журналов с использованием org.hibernate:hibernate-core:5.5.0-SNAPSHOT:20201117.201048-196 :

Feersum Endjinn is a great book!
[ERROR] failed to execute statement [select author0_.id as id1_0_0_, author0_.name as name2_0_0_ from authors author0_ where author0_.id in (?,?)]
[ERROR] could not load an entity batch: [org.hibernate.example.reactive.Author#<1, 3>]
java.util.concurrent.CompletionException: org.hibernate.LazyInitializationException: Collection cannot be initialized: org.hibernate.example.reactive.Author.books
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273) ~[?:1.8.0_275]
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280) ~[?:1.8.0_275]
    at java.util.concurrent.CompletableFuture.uniAccept(CompletableFuture.java:673) ~[?:1.8.0_275]
    at java.util.concurrent.CompletableFuture.uniAcceptStage(CompletableFuture.java:683) ~[?:1.8.0_275]
    at java.util.concurrent.CompletableFuture.thenAccept(CompletableFuture.java:2010) ~[?:1.8.0_275]
    at java.util.concurrent.CompletableFuture.thenAccept(CompletableFuture.java:110) ~[?:1.8.0_275]
    at org.hibernate.reactive.loader.ReactiveLoaderBasedResultSetProcessor.reactiveInitializeEntitiesAndCollections(ReactiveLoaderBasedResultSetProcessor.java:150) ~[hibernate-reactive-core-1.0.0-SNAPSHOT.jar:1.0.0-SNAPSHOT]
    at org.hibernate.reactive.loader.ReactiveLoaderBasedResultSetProcessor.reactiveExtractResults(ReactiveLoaderBasedResultSetProcessor.java:83) ~[hibernate-reactive-core-1.0.0-SNAPSHOT.jar:1.0.0-SNAPSHOT]
Error: Exception in thread "main" java.util.concurrent.CompletionException: org.hibernate.LazyInitializationException: Collection cannot be initialized: org.hibernate.example.reactive.Author.books
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
    at org.hibernate.reactive.loader.ReactiveLoader.reactiveProcessResultSet(ReactiveLoader.java:123) ~[hibernate-reactive-core-1.0.0-SNAPSHOT.jar:1.0.0-SNAPSHOT]
    at org.hibernate.reactive.loader.ReactiveLoader.lambda$doReactiveQueryAndInitializeNonLazyCollections$0(ReactiveLoader.java:71) ~[hibernate-reactive-core-1.0.0-SNAPSHOT.jar:1.0.0-SNAPSHOT]
    at java.util.concurrent.CompletableFuture.uniCompose(CompletableFuture.java:966) ~[?:1.8.0_275]
    at java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:940) ~[?:1.8.0_275]
    at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) ~[?:1.8.0_275]
    at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1975) ~[?:1.8.0_275]

...

Caused by: org.hibernate.LazyInitializationException: Collection cannot be initialized: org.hibernate.example.reactive.Author.books
    at org.hibernate.reactive.session.impl.ReactiveSessionImpl.initializeCollection(ReactiveSessionImpl.java:320)
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)

Все 37 Комментарий

Goops, вы правы: мы с @Sanne пропустили это из-за других ложных сбоев в CI.

Рискну предположить, что это связано с № 443.

Связана ли эта проблема с DirtyChecking?
Я думаю, что проблема связана с этим: https://github.com/hibernate/hibernate-reactive/issues/447

Во всяком случае, это происходит после обновления до ORM 5.4.24.

Связана ли эта проблема с DirtyChecking?

Ну, я подумал, что ошибка связана с пакетной загрузкой. Хотя я могу ошибаться.

Связана ли эта проблема с DirtyChecking?

Ну, я подумал, что ошибка связана с пакетной загрузкой. Хотя я могу ошибаться.

Ну ладно, похоже, я ошибаюсь, и проблема действительно в другом.

Я работаю над тестовым примером. Надеюсь, я смогу подтвердить это достаточно скоро.

Это имеет смысл, потому что только пример не работает, и это единственное место, где мы включаем улучшения байт-кода.

Ок, отлично.

Так да. Проблема заключается в грязной проверке коллекции, когда включены улучшения байтового кода. Не знаю, почему раньше это работало. Вероятно, эта ошибка в ORM скрывала проблему, и теперь, когда она исправлена, мы ее видим.

Уфф, что за PITA.

OTOH, почему грязная проверка коллекции даже _matter_, когда у нас еще даже нет CollectionPersister s?

Вот в чем проблема:

Улучшенный метод $$_hibernate_hasDirtyAttributes изменился с

    public boolean $$_hibernate_hasDirtyAttributes() {
        boolean var1 = false;
        var1 = this.$$_hibernate_tracker != null && !this.$$_hibernate_tracker.isEmpty();
        return var1;
    }

к

    public boolean $$_hibernate_hasDirtyAttributes() {
        boolean var1 = false;
        var1 = this.$$_hibernate_tracker != null && !this.$$_hibernate_tracker.isEmpty() || this.$$_hibernate_areCollectionFieldsDirty();
        return var1;
    }

    public boolean $$_hibernate_areCollectionFieldsDirty() {
        boolean var1 = false;
        if (!var1 && this.$$_hibernate_collectionTracker != null) {
            if (this.movies == null && this.$$_hibernate_collectionTracker.getSize("movies") != -1) {
                var1 = true;
            } else if (this.movies != null && this.$$_hibernate_collectionTracker.getSize("movies") != this.movies.size()) {
                var1 = true;
            }
        }

        return var1;
    }

вызов this.movies.size() вызывает LazyInitializationException

movies - это имя ассоциации внутри созданного мной теста.

@DavideD, так вы думаете, что здесь происходит просто то, что у нас нет прозрачного ленивого init (т.е. отсутствует вызов fetch() ), или это что-то более глубокое?

@DavideD Я прокомментировал https://github.com/hibernate/hibernate-orm/pull/3645 , потому что этот вызов size() мне не подходит. (Но я легко мог что-то упустить.)

@DavideD, так вы думаете, что здесь происходит просто то, что у нас нет прозрачного ленивого init (т.е. отсутствует вызов fetch ()), или это что-то более глубокое?

Думаю, в этом проблема. Я пытаюсь посмотреть, могу ли я получить коллекцию где-нибудь, чтобы она уже была получена.
Кстати, все работает, если я установил ассоциацию для получения EAGER.

Я пытаюсь посмотреть, могу ли я получить коллекцию где-нибудь, чтобы она уже была получена.

Хорошо, но не убивайте себя прямо сейчас, потому что мне все еще кажется неправильным, что мы извлекаем невыгруженную ассоциацию с mappedBy только для грязной проверки ее элементов. Посмотрим, что скажут @beikov и @Sanne .

(OTOH, даже если ядро ​​не работает правильно _ в этом конкретном случае_, нам все равно может понадобиться исправление, над которым вы работаете в других случаях.)

Спасибо @gavinking

Почему коллекция фильмов != null ? Я попытался воспроизвести это в ядре, но не смог, потому что такая коллекция никогда не должна быть ненулевой, если ленив.

Хорошо, я припоминаю, что где-то была какая-то длинная дискуссия. Я открыл проблему, в которой утверждал, что эта «двойная лень» или коллекции, по крайней мере, вероятно, плохи в Hibernate ORM и намного хуже для HR, где выборка непрозрачна. Нам нужно позволить вам получить ссылку на коллекцию, чтобы вызвать для нее fetch() .

ОК нашел. Так могло ли это быть связано с № 374?

Всегда ли collectionsInDefaultFetchGroupEnabled истинно в RX?

Хм, если я установлю значение true, коллекция будет инициализирована с нетерпением.

Всегда ли collectionsInDefaultFetchGroupEnabled истинно в RX?

Ага, это так.

Хм, если я установлю значение true, коллекция будет инициализирована с нетерпением.

Эмммм ... правда? Это не было намерением!

collectionsInDefaultFetchGroupEnabled должен просто включать прокси коллекции в группу выборки по умолчанию. На самом деле он не должен получать саму коллекцию.

Так что либо я полностью облажался, либо что-то изменилось с тех пор, как я написал этот код.

Я согласен с тем, что текущий подход к расширению не идеален и что поле должно быть инициализировано для постоянной коллекции, но я думаю, что проблема, с которой вы сталкиваетесь в RX, может быть вызвана чем-то другим. Когда я устанавливаю флаг в значение true, я вижу, что коллекция инициализируется с помощью этой трассировки:

org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
org.hibernate.collection.internal.AbstractPersistentCollection$1.doWork(AbstractPersistentCollection.java:178)
org.hibernate.collection.internal.AbstractPersistentCollection$1.doWork(AbstractPersistentCollection.java:163)
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264)
org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:162)
org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:371)
org.hibernate.test.bytecode.enhancement.dirty.DirtyTrackingCollectionTest$StringsEntity.$$_hibernate_removeDirtyFields(DirtyTrackingCollectionTest.java)
org.hibernate.test.bytecode.enhancement.dirty.DirtyTrackingCollectionTest$StringsEntity.$$_hibernate_clearDirtyCollectionNames(DirtyTrackingCollectionTest.java)
org.hibernate.test.bytecode.enhancement.dirty.DirtyTrackingCollectionTest$StringsEntity.$$_hibernate_clearDirtyAttributes(DirtyTrackingCollectionTest.java)
org.hibernate.tuple.entity.PojoEntityTuplizer.afterInitialize(PojoEntityTuplizer.java:228)
org.hibernate.persister.entity.AbstractEntityPersister.afterInitialize(AbstractEntityPersister.java:5093)
org.hibernate.engine.internal.TwoPhaseLoad.afterInitialize(TwoPhaseLoad.java:405)
org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.afterInitialize(AbstractRowReader.java:271)
org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:214)
org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:96)
org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:105)
org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:285)
org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:4441)
org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4431)
org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:569)
org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:537)
org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:208)
org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:332)
org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:108)
org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:74)
org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:121)
org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1186)
org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1175)
org.hibernate.internal.SessionImpl.access$2100(SessionImpl.java:193)
org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2786)
org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.lambda$load$1(SessionImpl.java:2767)
org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.perform(SessionImpl.java:2723)
org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2767)
org.hibernate.internal.SessionImpl.find(SessionImpl.java:3322)
org.hibernate.internal.SessionImpl.find(SessionImpl.java:3284)
org.hibernate.test.bytecode.enhancement.dirty.DirtyTrackingCollectionTest.lambda$test$1(DirtyTrackingCollectionTest.java:57)
org.hibernate.testing.transaction.TransactionUtil.doInJPA(TransactionUtil.java:235)
org.hibernate.testing.transaction.TransactionUtil.doInJPA(TransactionUtil.java:276)
org.hibernate.test.bytecode.enhancement.dirty.DirtyTrackingCollectionTest.test(DirtyTrackingCollectionTest.java:56)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
org.hibernate.testing.junit4.ExtendedFrameworkMethod.invokeExplosively(ExtendedFrameworkMethod.java:45)
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)
org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.lang.Thread.run(Thread.java:748)

Итак, $$_hibernate_removeDirtyFields() вызывает size() в неинициализированной коллекции. _Should_ это быть?

Я согласен с тем, что текущий подход к расширению не идеален и что поле должно быть инициализировано для постоянной коллекции, но я думаю, что проблема, с которой вы сталкиваетесь в RX, может быть вызвана чем-то другим. Когда я устанавливаю флаг в значение true, я вижу, что коллекция инициализируется с помощью этой трассировки:

Я, наверное, что-то упускаю, но разве это не та же проблема?
Он все еще вызывает size() но другим методом

Ты прав. Очевидно, коллекции не зарегистрированы как ленивые, что вызывает эту проблему. Я сейчас расследую.

Вот PR, который должен исправить эти проблемы: https://github.com/hibernate/hibernate-orm/pull/3664

Спасибо @beikov , похоже, тест работает с этой веткой

@beikov отлично, спасибо

Спасибо @beikov , похоже, тест работает с этой веткой

@DavideD, можешь ли ты @beikov только что обновил PR, посмотрим,

Вот PR, который должен исправить эти проблемы: hibernate / hibernate-orm # 3664

Подтверждено, нам просто нужен выпуск hibernate-core .

Исправлено # 463

Спасибо всем

Была ли эта страница полезной?
0 / 5 - 0 рейтинги