En toute sécurité de compensation de la session Hibernate dans le milieu de la grande opération
Je suis à l'aide de Spring+Hibernate pour une opération qui nécessite la création et la mise à jour des centaines de milliers d'articles. Quelque chose comme ceci:
{
...
Foo foo = fooDAO.get(...);
for (int i=0; i<500000; i++) {
Bar bar = barDAO.load(i);
if (bar.needsModification() && foo.foo()) {
bar.setWhatever("new whatever");
barDAO.update(bar);
//commit here
Baz baz = new Baz();
bazDAO.create(baz);
//if (i % 100 == 0), clear
}
}
}
Pour me protéger contre les perdre les modifications dans le milieu, j'valider les modifications immédiatement après barDAO.update(bar)
:
HibernateTransactionManager transactionManager = ...; //injected by Spring
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
transactionManager.commit(transactionStatus);
À ce point, je dois dire que tout le processus est en cours d'exécution dans une transaction enveloppé dans org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter
(oui, c'est une webapp).
Tout cela fonctionne très bien avec une seule exception: après quelques milliers de mises à jour/s'engage, tout le processus est très lent, très probablement due à mémoire de ballonnement l'augmentation constante du nombre d'objets conservés par Spring/Hibernate.
En veille prolongée environnement uniquement ce serait facilement résoluble en appelant org.hibernate.Session#clear()
.
Maintenant, les questions:
- Quand est-il un bon moment pour
clear()
? A-t-elle une grande performance coût? - Pourquoi ne sont pas des objets comme des
bar
oubaz
libéré/Pgcd automatiquement? Quel est le point de les maintenir dans la session après la validation (dans la boucle d'itération ils ne sont pas accessible de toute façon)? Je n'ai pas fait de vidage de mémoire pour prouver cela, mais mon sentiment est qu'ils sont encore là jusqu'à ce que complètement quitté. Si la réponse est "Hibernate cache", alors pourquoi n'est-ce pas le cache est vidé sur la mémoire disponible va faible? - est-il sécuritaire/recommandé d'appeler
org.hibernate.Session#clear()
directement (en ayant à l'esprit tout le Printemps contexte, des choses comme le chargement paresseux, etc.)? Sont-il utilisable Printemps wrappers/contreparties pour atteindre le même? - Si la réponse à la question ci-dessus est vrai, ce qui va se passer avec l'objet
foo
, en supposantclear()
est appelée à l'intérieur de la boucle? Que faire sifoo.foo()
est un paresseux-la méthode de chargement?
Merci pour les réponses.
- Je suis également de la réalisation de plusieurs grands inserts. L'ajout de code pour rincer et effacer la séance occasionnellement viens de faire mon code exécuté à 4x plus rapide!
Vous devez vous connecter pour publier un commentaire.
À intervalles réguliers, idéalement le même que le JDBC de la taille du lot, après avoir vidé les modifications. La documentation décrit des expressions communes dans le chapitre sur Le traitement par lot:
Et cela ne devrait pas avoir un rendement coût, au contraire:
Vous devez
clear()
la session explicitement si vous ne souhaitez pas conserver les entités suivies, c'est tout, c'est comment ça fonctionne (on peut avoir envie de commettre une transaction sans "perdre" les entités).Mais de ce que je peux voir, bar et baz instances doit devenir candidat à la GC après le clair. Il serait intéressant d'analyser un dump de la mémoire pour voir ce qui se passe exactement.
Aussi longtemps que vous
flush()
les modifications en attente de ne pas la perdre (sauf si c'est ce que vous voulez), je ne vois pas de problème avec ça (votre code actuel va perdre un de créer tous les 100 boucle, mais peut-être que c'est juste un pseudo-code).Appel
clear()
expulse toutes les instances chargées de laSession
, les rendant détaché des entités. Si une invocation exige d'une entité à être "connecté", il échouera.Je voulais juste faire remarquer que, après la libération de la session, si vous souhaitez continuer à utiliser certains objets qui étaient dans la session, vous aurez à
Session.refresh(obj)
afin de pouvoir poursuivre.Autrement, vous obtiendrez l'erreur suivante:
Session.refresh(obj)