Question

J'utilise SQLAlchemy en tant qu'ORM au sein d'une application que je construis depuis un certain temps.

Jusqu'à présent, la mise en œuvre et l'utilisation d'un ORM ont été relativement simples. Cependant, une fonctionnalité récente sur laquelle je travaille nécessite une approche persistante & amp; Implémentation de style file d'attente distribuée (list & amp; worker), que j'ai construite avec MySQL et Python.

Tout a très bien fonctionné jusqu'à ce que je le teste dans un environnement à l'échelle. J'ai utilisé le verrouillage de niveau ligne InnoDB pour garantir que chaque ligne n'est lue qu'une fois, tandis que la ligne est verrouillée, je mets à jour une valeur ' in_use ', afin de m'assurer que les autres ne saisissez pas l'entrée.

Etant donné que MySQL n'offre pas de "NOWAIT" méthode, comme Postgre ou Oracle, j'ai rencontré des problèmes de verrouillage dans lesquels les threads de travail se bloquent et attendent que la ligne verrouillée soit disponible.

Pour tenter de surmonter cette limitation, j'ai essayé de regrouper tous les traitements requis dans une seule instruction et de l'exécuter via la méthode execute () de l'ORM. , bien que SQLAlchemy refuse de renvoyer le résultat de la requête.

Voici un exemple.

Mon instruction SQL est la suivante:

SELECT id INTO @update_id FROM myTable WHERE in_use=0 ORDER BY id LIMIT 1 FOR UPDATE;
UPDATE myTable SET in_use=1 WHERE id=@update_id;
SELECT * FROM myTable WHERE id=@update_id;

Et je lance ce code dans la console:

engine = create_engine('mysql://<user details>@<server details>/myDatabase', pool_recycle=90, echo=True)
result = engine.execute(sqlStatement)
result.fetchall()

Seulement pour obtenir ce résultat

[]

Je suis certain que l'instruction est en cours d'exécution car je peux voir que la mise à jour prend effet dans la base de données, et si j'exécute via le terminal mysql ou d'autres outils, la ligne modifiée est renvoyée. SQLAlchemy semble ne pas vouloir accuser réception de la ligne renvoyée.

Y a-t-il quelque chose de spécifique à faire pour que l'ORM reçoive la réponse?

A bientôt

Était-ce utile?

La solution

Vous avez exécuté 3 requêtes et MySQLdb crée un jeu de résultats pour chacune d’elles. Vous devez récupérer le premier résultat, puis appeler cursor.nextset () , récupérer second et ainsi de suite.

Ceci répond à votre question, mais ne vous sera pas utile, car cela ne résoudra pas le problème du verrouillage. Vous devez d'abord comprendre comment FOR UPDATE fonctionne: il verrouille les lignes renvoyées jusqu'à la fin de la transaction. Pour éviter un long verrouillage, vous devez le rendre aussi bref que possible: SELECT ... FOR UPDATE , UPDATE SET in_use = 1 ... , COMMIT . En fait, vous n'avez pas besoin de les mettre dans une seule instruction SQL, 3 appels execute () seront également OK. Mais vous devez vous engager avant de longs calculs, sinon le verrouillage sera maintenu trop longtemps et la mise à jour de in_use (verrouillage hors ligne) n'a pas de sens. Et bien sûr, vous pouvez aussi faire la même chose avec ORM.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top