2016-11-29 27 views
1

Я использую Pony ORM версии 0.7 с базой данных Sqlite3 на диске и сталкиваюсь с этой проблемой: я выполняю выбор, затем обновление, а затем выберите, а затем еще одно обновление, и появляется сообщение об ошибке вPonyORM (Python) «Значение обновлялось за пределами текущей транзакции», но это не было

pony.orm.core.UnrepeatableReadError: Value of Task.order_id for 
    Task[23654] was updated outside of current transaction (was: 1, now: 2) 

Я свели задачу к минимальному набору команд, который вызывает проблему (т.е. удаление ничего вызывает проблему не произойти) :

@db_session 
def test_method(): 
    tasks = list(map(Task.to_dict, Task.select())) 
    db.execute("UPDATE Task SET order_id=order_id*2") 
    task_to_move = select(task for task in Task if task.order_id == 2).first() 
    task_to_move.order_id = 1 

test_method() 

Для полноты определения здесь дается определение Task:

class Task(db.Entity): 
    text = Required(unicode) 
    heading = Required(int) 
    create_timestamp = Required(datetime) 
    done_timestamp = Optional(datetime) 
    order_id = Required(int) 

Кроме того, если удалить ограничение, task.order_id == 2 от моего выбора, проблема больше не возникает, поэтому я предполагаю, что проблема имеет что-то делать с запрашивая на основе поля, которое было изменено с момента сделки , но я не знаю, почему сообщение об ошибке сообщает мне, что оно было изменено другой транзакцией (если, может быть, db.execute выполняется в отдельной транзакции, потому что это необработанный SQL?)

Я уже посмотрел по этому аналогичному вопросу, но проблема была другой (Pony ORM reports record "was updated outside of current transaction" while there is not other transaction) и в этой документации (https://docs.ponyorm.com/transactions.html), но не решили мою p РОБЛЕМА.

Любые идеи, что может быть здесь?

ответ

2

Пони используют оптимистичный контроль параллелизма по умолчанию. Для каждого атрибута Pony запоминает его текущее значение (возможно, измененное кодом приложения), а также оригинальное значение, которое было прочитано из базы данных. Во время UPDATE Pony проверяет, что значение столбца в базе данных остается неизменным. Если значение изменено, Пони предполагает, что некоторые параллельные транзакции это сделали, и выбрасывает исключение, чтобы избежать ситуации с «потерянным обновлением».

Если вы выполняете некоторый необработанный SQL-запрос, Pony не знает, что именно было изменено в базе данных. Поэтому, когда Пони сталкивается с изменением значения счетчика, он ошибочно полагает, что стоимость была изменена другой транзакцией.

Во избежание возникновения проблемы вы можете пометить order_id атрибут как volatile. Тогда Пони Предположим, что значение атрибута может измениться в любой момент (по триггеру или сырым обновлению SQL), и исключить этот атрибут из оптимистичных проверок:

class Task(db.Entity): 
    text = Required(unicode) 
    heading = Required(int) 
    create_timestamp = Required(datetime) 
    done_timestamp = Optional(datetime) 
    order_id = Required(int, volatile=True) 

Обратите внимание, что пони будет кэшировать значение volatile атрибута и не будет перечитывать значение из базы данных до тех пор, пока объект не будет сохранен, поэтому в некоторой ситуации вы можете получить устаревшее значение в Python.