Автор Pony ORM здесь.
Это поведение является специфичной для MySQL ошибкой, которая была исправлена в версии Pony ORM 0.4.9, поэтому обновите ее. Остальная часть моего ответа - это объяснение того, что вызвало ошибку.
Причина этой ошибки следующая. Чтобы предотвратить потерю обновлений, Pony ORM использует оптимистичные проверки. Pony отслеживает, какие атрибуты были прочитаны или изменены во время выполнения программы, а затем добавляет дополнительные условия в раздел WHERE
соответствующего запроса UPDATE
. Таким образом, Pony гарантирует, что никакие данные не будут потеряны из-за параллельного обновления. Рассмотрим следующий пример:
@db_session
def some_function()
obj = MyObject[123]
print obj.x
obj.x = 100
После выхода из some_function
декоратор @db_session
зафиксирует текущую транзакцию. Непосредственно перед фиксацией данные объекта будут сохранены следующей командой UPDATE
:
UPDATE MyTable
SET x = <new_value>
WHERE id = 123 and x = <old_value>
Вы можете задаться вопросом, зачем было добавлено это дополнительное условие and x = <old_value>
? Это связано с тем, что Pony знает, что программа видела предыдущее значение атрибута x
и может использовать это значение для вычисления нового значения того же атрибута. Поэтому Pony предпринимает шаги, чтобы гарантировать, что этот атрибут не изменится в момент UPDATE
. Этот подход называется "оптимистическая проверка параллелизма" (см. также статью Википедии "оптимистичный контроль параллелизма"). Поскольку уровень изоляции, используемый по умолчанию в большинстве баз данных, не SERIALIZABLE
, без этой дополнительной проверки возможно, что какая-то другая транзакция успела обновить значение атрибута x
до фиксации нашей транзакции, и тогда значение, записанное параллельной транзакцией, будет потеряно. .
Когда драйвер базы данных Python выполняет запрос UPDATE
, он возвращает количество строк, удовлетворяющих критериям UPDATE
. Таким образом, Pony узнает, было ли обновление успешным или нет. Если результат равен 1, это означает, что одна строка была успешно найдена и обновлена, но если результат равен 0, это означает, что строка уже была изменена другой транзакцией и теперь она не удовлетворяет критериям раздела WHERE
. Когда это происходит, Pony завершает текущую транзакцию, чтобы предотвратить потерю обновления.
Причина ошибки в том, что в то время как все другие драйверы баз данных возвращают количество строк, которые были найдены по критерию секции WHERE
, драйвер MySQLdb
по умолчанию возвращает количество строк, которые были фактически изменены! Из-за этого, если новое значение атрибута оказывается таким же, как исходное значение того же атрибута, MySQLdb
сообщает, что было изменено 0 строк, а Pony (до релиза 0.4.9) ошибочно полагает, что это означает что строка была изменена параллельной транзакцией. Начиная с версии 0.4.9 Pony ORM указывает драйверу MySQLdb
вести себя стандартным образом и возвращать количество строк, которые были найдены, а не количество строк, которые были фактически обновлены.
Надеюсь это поможет :)
P.S. Я случайно нашел ваш вопрос, чтобы надежно получить ответы о Pony ORM, я рекомендую вам присылать вопросы в наш список рассылки http://ponyorm-list.ponyorm.com. Если вы считаете, что нашли ошибку, вы можете открыть проблему здесь: https://github.com/ponyorm/pony/issues. Спасибо Вам за Ваш вопрос!
person
Alexander Kozlovsky
schedule
16.11.2013