sessionmaker()
est une usine, elle est là pour encourager la mise en place d'options de configuration pour créer de nouvelles Session
des objets à un seul endroit. Il est facultatif, dans la mesure où vous pourriez tout aussi bien appeler Session(bind=engine, expire_on_commit=False)
chaque fois que vous avez besoin d'un nouveau Session
sauf que c'est verbeux et redondant, et je voulais arrêter la prolifération de petites "aides" qui abordaient chacune le problème de cette redondance d'une manière nouvelle et plus confuse.
Alors sessionmaker()
est juste un outil pour vous aider à créer Session
des objets quand vous en avez besoin.
Partie suivante. Je pense que la question est, quelle est la différence entre faire une nouvelle Session()
à différents moments, plutôt que d'en utiliser une seule tout au long du processus. La réponse est : pas beaucoup. Session
est un conteneur pour tous les objets que vous y mettez, et il garde aussi la trace d'une transaction ouverte. Au moment où vous appelez rollback()
o commit()
la transaction est terminée, et le Session
n'a aucune connexion avec la base de données jusqu'à ce qu'il soit appelé à émettre à nouveau du SQL. Les liens qu'il entretient avec vos objets mappés sont des références faibles, à condition que les objets soient exempts de modifications en attente. Session
se videra pour revenir à un tout nouvel état lorsque votre application perdra toutes les références aux objets mappés. Si vous le laissez avec sa valeur par défaut "expire_on_commit"
alors tous les objets sont expirés après un commit. Si cette Session
qui traîne pendant cinq ou vingt minutes, et que toutes sortes de choses ont changé dans la base de données, la prochaine fois que vous l'utiliserez, elle chargera un tout nouvel état la prochaine fois que vous accéderez à ces objets, même s'ils sont restés en mémoire pendant vingt minutes.
Dans les applications web, on a l'habitude de dire, hey pourquoi ne pas faire un tout nouveau Session
à chaque demande, plutôt que d'utiliser le même à chaque fois. Cette pratique garantit que la nouvelle requête commence "proprement". Si certains objets de la requête précédente n'ont pas encore été collectés, et si vous avez peut-être désactivé la fonction "expire_on_commit"
Si vous ne faites pas attention, il se peut qu'un état de la requête précédente soit toujours présent, et cet état peut même être assez ancien. Si vous faites attention à laisser expire_on_commit
allumé et pour appeler définitivement commit()
o rollback()
à la fin de la demande, alors c'est bien, mais si vous commencez avec une toute nouvelle Session
alors il n'y a aucun doute sur le fait que vous partez de zéro. Donc l'idée de commencer chaque demande avec une nouvelle Session
est vraiment le moyen le plus simple de s'assurer que vous repartez à zéro, et de faire l'utilisation de expire_on_commit
plutôt facultatif, car ce drapeau peut entraîner beaucoup de SQL supplémentaire pour une opération qui fait appel à commit()
au milieu d'une série d'opérations. Je ne sais pas si cela répond à votre question.
La prochaine étape est ce que vous mentionnez au sujet de l'enfilage. Si votre application est multithreadée, nous vous recommandons de vous assurer que l'option Session
utilisé est local à... quelque chose. scoped_session()
par défaut le rend local au thread actuel. Dans une application web, il est encore mieux de le faire localement, au niveau de la requête. Flask-SQLAlchemy envoie en fait une "fonction de portée" personnalisée à scoped_session()
afin d'obtenir une session à l'échelle de la demande. L'application Pyramid moyenne place la session dans le registre "request". Lorsque l'on utilise des schémas de ce type, l'idée de "créer une nouvelle session au début de la demande" continue de sembler être le moyen le plus simple de garder les choses en ordre.