Exemple d'un des logs utilisant 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)
Goops, vous avez raison : @Sanne et moi avons tous les deux raté cela à cause d'autres échecs fallacieux dans le CI.
Je risque de supposer que cela est lié à #443.
Ce problème est-il lié à DirtyChecking ?
Je pense que ce problème est lié à ceci : https://github.com/hibernate/hibernate-reactive/issues/447
Quoi qu'il en soit, cela arrive après la mise à jour vers ORM 5.4.24
Ce problème est-il lié à DirtyChecking ?
Eh bien, j'ai pensé que le bogue était lié au chargement par lots. Je me trompe peut-être cependant.
Ce problème est-il lié à DirtyChecking ?
Eh bien, j'ai pensé que le bogue était lié au chargement par lots. Je me trompe peut-être cependant.
Bon, on dirait que je me trompe et le problème est bel et bien ailleurs.
Je travaille sur un cas de test. J'espère pouvoir le confirmer assez tôt.
Cela a du sens car seul l'exemple échoue et c'est le seul endroit où nous activons les améliorations du bytecode
D'accord, super.
Donc oui. Le problème est la vérification sale de la collection lorsque les améliorations du byte code sont activées. Je ne sais pas pourquoi ça fonctionnait avant. Probablement, ce bogue dans ORM cachait le problème et maintenant qu'il est corrigé, nous le voyons.
Uff, quel PITA.
OTOH, pourquoi la collection vérifie-t-elle même la _matière_ alors que nous n'avons même pas encore de CollectionPersister
?
C'est le problème :
La méthode améliorée $$_hibernate_hasDirtyAttributes
a changé, de
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;
}
l'appel à this.movies.size()
provoque un LazyInitializationException
movies
est le nom de l'association à l'intérieur du test que j'ai créé
@DavideD alors pensez-vous que ce qui se passe ici est simplement que nous n'avons pas d'initialisation paresseuse transparente (c'est-à-dire qu'il manque un appel à fetch()
), ou est-ce quelque chose de plus profond?
@DavideD J'ai commenté https://github.com/hibernate/hibernate-orm/pull/3645 , car cet appel à size()
ne me semble pas correct. (Mais je pourrais facilement manquer quelque chose.)
@DavideD alors pensez-vous que ce qui se passe ici est simplement que nous n'avons pas d'initialisation paresseuse transparente (c'est-à-dire qu'il manque un appel à fetch()), ou est-ce quelque chose de plus profond?
Je pense que c'est le problème. J'essaie de voir si je peux récupérer la collection quelque part afin qu'elle soit déjà récupérée.
Au fait, tout fonctionne si je configure l'association pour la récupération EAGER.
J'essaie de voir si je peux récupérer la collection quelque part afin qu'elle soit déjà récupérée.
OK, mais ne vous tuez pas là-dessus _tout de suite_ parce qu'il me semble toujours mal que nous récupérons une association non récupérée avec mappedBy
juste pour vérifier ses éléments. Voyons ce que @beikov et @Sanne ont à dire.
(OTOH, même si le noyau ne fait pas la bonne chose _dans ce cas particulier_, nous pourrions toujours avoir besoin du correctif sur lequel vous travaillez dans d'autres cas.)
Pour plus d'informations, il s'agit d'une branche avec le cas de test (encore un travail en cours) : https://github.com/DavideD/hibernate-reactive/tree/447-dirtychecking
Merci @gavinking
Pourquoi la collection de films est-elle != null
? J'ai essayé de reproduire cela dans le noyau, mais je n'ai pas pu car une telle collection ne devrait jamais être non nulle si paresseuse.
Eh bien, je me souviens qu'il y a eu une assez longue discussion quelque part. Un problème que j'ai ouvert où j'ai soutenu que cette "double paresse" ou ces collections étaient au moins sans doute mauvaises dans Hibernate ORM, et un problème bien pire pour les RH, où la récupération n'est pas transparente. Nous devons vous permettre d'obtenir une référence à la collection pour appeler fetch()
dessus.
OK trouvé. Cela pourrait-il être lié à #374 ?
Est-ce que collectionsInDefaultFetchGroupEnabled
toujours vrai dans RX ?
Hmm, si je le mets sur true, la collection est initialisée avec impatience.
Est-ce que
collectionsInDefaultFetchGroupEnabled
toujours vrai dans RX ?
Ouais, ça l'est.
Hmm, si je le mets sur true, la collection est initialisée avec impatience.
Hummm... vraiment ? Ce n'était pas l'intention !
collectionsInDefaultFetchGroupEnabled
est censé simplement inclure le proxy de collection dans le groupe d'extraction par défaut. Il n'est pas censé récupérer la collection elle-même.
Donc soit j'ai complètement merdé, soit quelque chose a changé depuis que j'ai écrit ce code.
Je suis avec vous que l'approche actuelle de l'amélioration n'est pas idéale et que le champ doit être initialisé sur une collection persistante, mais je pense que le problème que vous rencontrez dans RX pourrait être causé par autre chose. Lorsque je mets l'indicateur sur true, je vois la collection en cours d'initialisation via cette trace :
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)
Donc $$_hibernate_removeDirtyFields()
appelle size()
sur une collection non initialisée. _Devrait-ce être?
Je suis avec vous que l'approche actuelle de l'amélioration n'est pas idéale et que le champ doit être initialisé sur une collection persistante, mais je pense que le problème que vous rencontrez dans RX pourrait être causé par autre chose. Lorsque je mets l'indicateur sur true, je vois la collection en cours d'initialisation via cette trace :
Il me manque probablement quelque chose, mais n'est-ce pas le même problème ?
Il appelle toujours size()
mais à partir d'une méthode différente
Vous avez raison. Apparemment, les collections ne sont pas enregistrées comme étant paresseuses, ce qui provoque ce problème. J'enquête maintenant.
Voici un PR qui devrait résoudre ces problèmes : https://github.com/hibernate/hibernate-orm/pull/3664
Merci @beikov , le test semble fonctionner en utilisant cette branche
@beikov excellent, merci
Merci @beikov , le test semble fonctionner en utilisant cette branche
@DavideD pouvez-vous retester maintenant, @beikov vient de
Voici un PR qui devrait résoudre ces problèmes : hibernate/hibernate-orm#3664
Confirmé, nous avons juste besoin d'une version de hibernate-core
.
Corrigé par #463
Merci a tous