Hibernate-reactive: Exemplo falha com ORM 5.4.24

Criado em 20 nov. 2020  ·  37Comentários  ·  Fonte: hibernate/hibernate-reactive

Exemplo de um dos registros usando 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)
bug

Todos 37 comentários

Bolas, você está certo: @Sanne e eu perdemos isso por causa de outras falhas espúrias no IC.

Eu arrisco um palpite de que isso está relacionado a # 443.

Esse problema está relacionado ao DirtyChecking?
Acho que esse problema está relacionado a isso: https://github.com/hibernate/hibernate-reactive/issues/447

De qualquer forma, isso acontece após a atualização para ORM 5.4.24

Esse problema está relacionado ao DirtyChecking?

Bem, descobri que o bug está relacionado ao carregamento em lote. Eu posso estar errado embora.

Esse problema está relacionado ao DirtyChecking?

Bem, descobri que o bug está relacionado ao carregamento em lote. Eu posso estar errado embora.

Bem, parece que estou errado e o problema está realmente em outro lugar.

Estou trabalhando em um caso de teste. Espero poder confirmar isso em breve.

Mas faz sentido porque apenas o exemplo falha e é o único lugar onde ativamos os aprimoramentos de bytecode

OK ótimo.

Então sim. O problema é a verificação suja da coleção quando os aprimoramentos do código de byte estão habilitados. Não sei por que estava funcionando antes. Provavelmente, esse bug no ORM estava escondendo o problema e agora que foi corrigido, nós o vemos.

Uff, que PITA.

OTOH, por que a verificação suja da coleção ainda _material_ quando ainda não temos CollectionPersister s?

Este é o problema:

O método aprimorado $$_hibernate_hasDirtyAttributes mudou, de

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

para

    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;
    }

a chamada para this.movies.size() causa um LazyInitializationException

movies é o nome da associação dentro do teste que criei

@DavideD, então você acha que o que está acontecendo aqui é apenas que não temos init preguiçoso transparente (ou seja, está faltando uma chamada para fetch() ), ou é algo mais profundo?

@DavideD Comentei em https://github.com/hibernate/hibernate-orm/pull/3645 , porque aquela ligação para size() não parece certa para mim. (Mas eu poderia facilmente estar faltando alguma coisa.)

@DavideD, então você acha que o que está acontecendo aqui é apenas que não temos init preguiçoso transparente (ou seja, está faltando uma chamada para fetch ()), ou é algo mais profundo?

Acho que esse é o problema. Estou tentando ver se consigo buscar a coleção em algum lugar para que ela já seja buscada.
A propósito, tudo funciona se eu definir a associação para a busca EAGER.

Estou tentando ver se consigo buscar a coleção em algum lugar para que ela já seja buscada.

OK, mas não se mate nisso _ agora_ porque ainda parece errado para mim que estamos buscando uma associação não buscada com mappedBy apenas para verificar seus elementos. Vamos ver o que @beikov e @Sanne têm a dizer.

(OTOH, mesmo que o core não esteja fazendo a coisa certa _neste caso em particular_, ainda podemos precisar da correção que você está trabalhando em outros casos.)

Obrigado @gavinking

Por que a coleção de filmes é != null ? Tentei reproduzir isso no núcleo, mas não consegui porque essa coleção nunca deve ser não nula se preguiçosa.

Bem, eu me lembro que houve uma longa discussão em algum lugar. Um problema que abri onde argumentei que essa "preguiça dupla" ou coleções eram pelo menos indiscutivelmente ruins no Hibernate ORM, e um problema muito pior para o RH, onde a busca não é transparente. Precisamos permitir que você obtenha uma referência para a coleção para chamar fetch() nela.

OK, encontrei. Então, isso poderia estar relacionado ao # 374?

collectionsInDefaultFetchGroupEnabled sempre verdadeiro em RX?

Hmm, se eu definir como verdadeiro, a coleção é inicializada avidamente.

collectionsInDefaultFetchGroupEnabled sempre verdadeiro em RX?

Sim, é.

Hmm, se eu definir como verdadeiro, a coleção é inicializada avidamente.

Ummmm ... sério? Essa não foi a intenção!

collectionsInDefaultFetchGroupEnabled deve apenas incluir o proxy de coleção no grupo de busca padrão. Ele não deve realmente buscar a coleção em si.

Ou eu estraguei tudo ou algo mudou desde que escrevi aquele código.

Estou com você que a abordagem atual para aprimoramento não é ideal e que o campo deve ser inicializado para uma coleção persistente, mas acho que o problema que você está tendo no RX pode ser causado por outra coisa. Quando defino o sinalizador como verdadeiro, vejo a coleção sendo inicializada por meio deste rastreamento:

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)

Portanto, $$_hibernate_removeDirtyFields() está chamando size() em uma coleção não inicializada. _Deveria ser?

Estou com você que a abordagem atual para aprimoramento não é ideal e que o campo deve ser inicializado para uma coleção persistente, mas acho que o problema que você está tendo no RX pode ser causado por outra coisa. Quando defino o sinalizador como verdadeiro, vejo a coleção sendo inicializada por meio deste rastreamento:

Provavelmente estou faltando alguma coisa, mas não é o mesmo problema?
Ele ainda está chamando size() mas de um método diferente

Você está certo. Aparentemente, as coleções não são registradas como preguiçosas, o que causa esse problema. Estou investigando agora.

Aqui está um PR que deve corrigir esses problemas: https://github.com/hibernate/hibernate-orm/pull/3664

Obrigado @beikov , o teste parece funcionar usando esse branch

@beikov excelente, obrigado

Obrigado @beikov , o teste parece funcionar usando esse branch

@DavideD pode testar novamente agora, @beikov acabou de atualizar o PR, vamos ver se ainda resolve o problema.

Aqui está um PR que deve corrigir esses problemas: hibernate / hibernate-orm # 3664

Confirmado, só precisamos da liberação de hibernate-core .

Corrigido por # 463

Obrigado a todos

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

arifpratama398 picture arifpratama398  ·  10Comentários

akoufa picture akoufa  ·  30Comentários

DavideD picture DavideD  ·  17Comentários

yaakov-berkovitch picture yaakov-berkovitch  ·  16Comentários

tsegismont picture tsegismont  ·  9Comentários