python orm transactions ponyorm

python - El registro de informes ORM de Pony "se actualizó fuera de la transacción actual" mientras no haya otra transacción



transactions ponyorm (1)

El código es bastante simple, de la siguiente manera:

from pony.orm import Required, Set, Optional, PrimaryKey from pony.orm import Database, db_session import time db = Database(''mysql'', host="localhost", port=3306, user="root", passwd="123456", db="learn_pony") class TryUpdate(db.Entity): _table_ = "try_update_record" t = Required(int, default=0) db.generate_mapping(create_tables=True) @db_session def insert_record(): new_t = TryUpdate() @db_session def update(): t = TryUpdate.get(id=1) print t.t t.t = 0 print t.t if __name__ == "__main__": insert_record() update()

Excepción de informes pony.orm: pony.orm.core.CommitException: el objeto TryUpdate [1] se actualizó fuera de la transacción actual. Pero no hay otra transacción funcionando en absoluto

Y como muestran mis experimentos, pony funciona bien siempre que tt se cambie a un valor diferente del original, pero siempre informa excepción cuando tt se establece en un valor que es igual al original.

No estoy seguro si esta es una decisión de diseño. ¿Tengo que verificar si mi valor de entrada cambia cada vez antes de la asignación? ¿O hay algo que pueda hacer para evitar esta molesta excepción?

mi versión pony: 0.4.8

Thansk mucho ~~~


El autor de Pony ORM está aquí.

Este comportamiento es un error específico de MySQL que se solucionó en la versión Pony ORM 0.4.9, así que actualice. El resto de mi respuesta es la explicación de qué causó el error.

El motivo de este error es el siguiente. Para evitar actualizaciones perdidas, Pony ORM utiliza controles optimistas. Pony rastrea qué atributos se leyeron o modificaron durante la ejecución del programa y luego agrega condiciones adicionales en la sección WHERE de la consulta UPDATE correspondiente. De esta forma, Pony garantiza que no se perderán datos debido a la actualización simultánea. Consideremos el siguiente ejemplo:

@db_session def some_function() obj = MyObject[123] print obj.x obj.x = 100

Al salir de la función @db_session decorador @db_session confirmará la transacción en curso. Justo antes de la confirmación, los datos del objeto se guardarán con el siguiente comando UPDATE :

UPDATE MyTable SET x = <new_value> WHERE id = 123 and x = <old_value>

Quizás se pregunte por qué se agregó esta condición adicional and x = <old_value> . Esto se debe a que Pony sabe que el programa vio el valor anterior del atributo x puede usar este valor para calcular el nuevo valor del mismo atributo. Así que Pony toma medidas para garantizar que este atributo aún no se modifique en el momento de la UPDATE . Este enfoque se denomina "comprobación de concurrencia optimista" (consulte también el artículo de Wikipedia "control de concurrencia optimista" ). Como el nivel de aislamiento utilizado por defecto en la mayoría de las bases de datos no es SERIALIZABLE , sin esta verificación adicional es posible que alguna otra transacción haya logrado actualizar el valor del atributo x antes de que nuestra transacción se haya comprometido y luego se perderá el valor escrito por la transacción simultánea. .

Cuando el controlador de la base de datos Python ejecuta la consulta UPDATE , devuelve el número de filas que satisfacen los criterios de UPDATE . De esta forma, Pony sabe si la actualización fue exitosa o no. Si el resultado es 1, esto significa que se encontró y actualizó correctamente una fila, pero si el resultado es 0, esto significa que la fila ya fue modificada por otra transacción y ahora no cumple los criterios en la sección WHERE . Cuando esto sucede, Pony finaliza la transacción actual para evitar la actualización perdida.

El motivo del error es que, si bien todos los demás controladores de bases de datos devuelven el número de filas que encontraron los criterios de la sección WHERE , el controlador MySQLdb devuelve de manera predeterminada el número de filas que en realidad se modificaron. Debido a esto, si el nuevo valor del atributo resulta ser el mismo que el valor original del mismo atributo, MySQLdb informa que se modificaron 0 filas, y Pony (antes del lanzamiento 0.4.9) cree erróneamente que significa que la fila fue modificada por una transacción concurrente. Comenzó con el lanzamiento 0.4.9. Pony ORM le dice MySQLdb controlador MySQLdb que se comporte de una manera estándar y devuelva el número de filas que se encontraron y no el número de filas que realmente se actualizaron.

Espero que esto ayude :)

PD. Encontré tu pregunta por casualidad, para obtener respuestas confiables sobre Pony ORM. Te recomiendo que envíes preguntas a nuestra lista de correo http://ponyorm-list.ponyorm.com . Si cree que encontró un error, puede abrir el problema aquí: https://github.com/ponyorm/pony/issues . ¡Gracias por su pregunta!