Aujourd'hui, j'ai fait face au prochain problème en veille prolongée:
Ma méthode:
@Transactional
public Period getDefault(Team team) {
Period defaultPeriod = team.getDefaultPeriod();
List<Period> periods = _periodDAO.getPeriods(team);
if (!periods.contains(defaultPeriod)) {
defaultPeriod = periods.get(periods.size() - 1);
}
}
_periodDAO.initializeIssues(defaultPeriod);
return defaultPeriod;
}
Méthode initializeIssues:
public void initializeIssues(Period period) {
if (period.getIssues() != null) {
Hibernate.initialize(period.getIssues());
}
}
Je reçois une exception si collection périodes contient defaultPeriod
Caused by: org.hibernate.HibernateException: collection is not associated with any session
at org.hibernate.collection.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:474)
at org.hibernate.Hibernate.initialize(Hibernate.java:417)
Mais si je supprime quelques lignes et que je change de méthode,
@Transactional
public Period getDefault(Team team) {
Period defaultPeriod = team.getDefaultPeriod();
_periodDAO.initializeIssues(defaultPeriod);
return defaultPeriod;
}
Ça fonctionne bien.
J'ai débogué le premier exemple et la session de veille prolongée ne se ferme pas pendant toute la méthode.
Si je comprends bien, si objet chargé (un élément dans périodes) en session a une collection qui est associée à une session active et à un objet avant existant (defaultPeriod) a également la même association - il (defaultPeriod) va perdre son association.
Est-ce la vérité? Qui d'autre est confronté au même problème?
Merci pour les réponses.
Réponses:
13 pour la réponse № 1Vraisemblablement, votre Team
l'argument vient d'une autre transaction et d'un autre Hibernate Session
.
Lorsqu'un @Transactional
la méthode retourne, le TransactionManager
ferme le Session
qui fait un peu de nettoyage et désactive (définit à null
) la Session
domaine de tous PersistentCollection
les instances. Votre defaultPeriod
a l'un d'entre eux dans son issues
champ.
Hibernate "s Hibernate.initialize()
force l'initialisation d'un paresseux PersistentCollection
, mais a le code suivant (appelle AbstractPersistentCollection#forceInitialization()
)
if ( session == null ) {
throw new HibernateException( "collection is not associated with any session" );
}
Si vous prévoyez d’utiliser le issues
collection en dehors de l'original @Transactional
méthode (le code qui produit Team
), vous devez charger les objets sous-jacents. Changez-le en chargement EAGER ou faites ce que vous faites avec Hibernate.initialize()
.
Une autre solution consiste à rendre le Session
durer plus longtemps que juste la longueur de la première @Transactional
, mais je n’ai pas de détails à ce sujet. Une recherche rapide dans Google ou SO devrait faire apparaître certaines options.
C'est ce qui se passe
Period defaultPeriod = team.getDefaultPeriod();
Obtient un Period
objet avec id (ex.) 42
. Parce que c'est arrivé dans un autre Session
qui a depuis été fermé, le issues
est un PersistentCollection
qui a un null
Session
référence, et jettera le Exception
vous recevez.
Le tu fais cela
List<Period> periods = _periodDAO.getPeriods(team);
Disons le List
contient un Period
objet avec identifiant 42
, alors le if
dans
if (!periods.contains(defaultPeriod)) {
defaultPeriod = periods.get(periods.size() - 1);
}
ne pas "être exécuté. Bien que le equals()
résultats true
(contains()
retourne aussi true
et devient false
en raison de !
), les objets ne sont pas les mêmes. Le dans le List
a un attaché (non nul) Session
, afin que l'on puisse être initialisé. Mais le tien, celui tenu par defaultPeriod
ne peux pas.