Pregunta

Estoy usando SQLAlchemy como ORM dentro de una aplicación que he estado creando durante algún tiempo.

Hasta ahora, ha sido un ORM bastante sencillo de implementar y usar, sin embargo, una característica reciente en la que estoy trabajando requiere una persistente & amp; implementación de estilo de cola distribuida (lista & amp; trabajador), que he construido en MySQL y Python.

Todo funcionó bastante bien hasta que lo probé en un entorno a escala. He usado el bloqueo de nivel de fila de InnoDB para asegurar que cada fila se lea solo una vez, mientras la fila está bloqueada, actualizo un valor ' in_use ', para asegurarme de que otros no agarres la entrada.

Dado que MySQL no ofrece un " NOWAIT " método como lo hace Postgre u Oracle, me he encontrado con problemas de bloqueo donde los hilos de trabajo se cuelgan y esperan que la fila bloqueada esté disponible.

En un intento por superar esta limitación, he intentado poner todo el procesamiento requerido en una sola declaración y ejecutarlo a través del método execute() del ORM , aunque SQLAlchemy se niega a devolver el resultado de la consulta.

Aquí hay un ejemplo.

Mi declaración SQL es:

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;

Y ejecuto este código en la consola:

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

Solo para obtener este resultado

[]

Estoy seguro de que la declaración se está ejecutando, ya que puedo ver que la actualización surte efecto en la base de datos, y si ejecuto a través del terminal mysql u otras herramientas, me devuelve la fila modificada. Simplemente parece ser SQLAlchemy que no quiere reconocer la fila devuelta.

¿Hay algo específico que deba hacerse para garantizar que el ORM recoge la respuesta?

Saludos

¿Fue útil?

Solución

Ha ejecutado 3 consultas y MySQLdb crea un conjunto de resultados para cada una. Debe obtener el primer resultado, luego llamar a cursor.nextset () , obtener el segundo y así sucesivamente.

Esto responde a su pregunta, pero no será útil para usted, ya que no resolverá el problema de bloqueo. Primero debe comprender cómo funciona FOR UPDATE: bloquea las filas devueltas hasta el final de la transacción. Para evitar una larga espera de bloqueo, debe hacerlo lo más breve posible: SELECT ... FOR UPDATE , UPDATE SET in_use = 1 ... , COMMIT . En realidad, no necesita ponerlos en una sola declaración SQL, 3 llamadas execute () también estarán bien. Pero tiene que comprometerse antes de un cálculo largo, de lo contrario, el bloqueo se mantendrá demasiado tiempo y la actualización de in_use (bloqueo fuera de línea) no tiene sentido. Y seguro que también puedes hacer lo mismo con ORM.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top