2010-11-26 35 views
4

je je thread dans un démon, qui boucle et exécute la requête suivante:Comment désactiver la mise en cache correctement dans Sqlalchemy orm session?

try: 
     newsletter = self.session.query(models.Newsletter).\ 
       filter(models.Newsletter.status == 'PROCESSING').\ 
       limit(1).one() 
    except sa.orm.exc.NoResultFound: 
     self.logger.debug('No PROCESSING newsletters found. Sleeping...') 
     self.sleep() 
     return 
    # (...) more code to do with found newsletter 

Lorsque la méthode de sommeil arrête simplement l'exécution de ce fil pendant le temps configuré et les rendements des états de retour à la boucle principale. Cependant, j'ai trouvé que si je change le statut de la newsletter en 'TRAITEMENT' pendant que le démon fonctionne, rien ne se passe, c'est à dire. la requête soulève toujours NoResultFound. Si je redémarre le démon cependant, il trouvera la newsletter. Donc, je vois, que les résultats de cette requête doivent être mis en cache. Que puis-je faire pour invalider le cache? session.expire_all() ne fonctionne pas. Je pourrais aussi créer un nouvel objet Session() à chaque itération, mais je ne sais pas si c'est une bonne approche concernant les ressources du système.

+2

hypothèses Bad de votre part. Savez-vous comment votre base de données sérialise ces deux transactions? Savez-vous quels verrous de base de données sont impliqués dans ces deux transactions? Comment savez-vous que c'est un cache SQLAlchemy? Il est tout aussi susceptible d'être un verrou de base de données qui empêche la mise à jour jusqu'à ce que la requête se termine, car la requête supprime les mauvais verrous. Avez-vous des preuves de mise en cache? Ou est-ce une supposition? –

+0

Je n'ai aucune preuve. Juste une supposition. Peut-être que la mise en cache est faite ailleurs. Utiliser rollback() semble fonctionner ici. – zefciu

+0

Il est plus probable que ce soit ** pas ** la mise en cache, mais le verrouillage. –

Répondre

5

SQLAlchemy doesn't cache sur lui-même. Sauf si vous avez explicitement implémenté un cache, like this one.

Passez le echo=True à sessionmaker et regardez dans logging output.

+0

Passer echo = True ne fonctionne pas. J'ai également essayé d'installer la journalisation de sqlalchemy.engine logger, mais cela n'a pas fonctionné aussi. – zefciu

+0

avez-vous activé la journalisation? – knitti

+0

Vous devrez peut-être activer la consignation à l'échelle de l'application: https://gist.github.com/aphillipo/25ae5456cf1fe7fed1a5 – pip

1

Hmm J'ai déjà trouvé la réponse, vous devez apparemment faire explicitement session.commit() pour la mettre à jour, ou vous devez définir autocommit = True sur la session, par exemple par le programme de création de session.

sessionmaker(bind=self.engine, autocommit=True) 

Cependant, je ne l'ai pas testé la voie session.commit()

Donc, ce n'est pas un problème de mise en cache, il semble être juste les transactions façon dont fonctionnent

3

Le problème dans votre code est dû à la base de données en utilisant REPEATABLE READ isolation level par défaut, donc la requête renvoie le même résultat sauf si vous appelez commit() ou rollback() (ou utilisez autocommit=True comme Xeross suggéré) ou manuellement changer le niveau d'isolement.

Oui, SQLAlchemy met en cache les objets mappés (pas les résultats de la requête!), Car le modèle ORM requiert un objet unique pour chaque identité. Par défaut, SQLAlchemy utilise une carte d'identité faible comme cache, de sorte que l'objet est automatiquement supprimé de la session lorsqu'il ne lui reste plus de références. Notez que les requêtes suivantes mettront à jour l'état des objets mis en cache avec de nouvelles données, donc pas besoin de s'inquiéter de ce cache.

1

ne pas utiliser autocommit = True et expire_on_commit = True

for state in self.identity_map.all_states(): 
    state.expire(state.dict, self.identity_map._modified) 

vous pouvez: après la requête: db.session.commit()