1

ディスク上の Sqlite3 データベースで Pony ORM バージョン 0.7 を使用していますが、この問題が発生しています。

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)

また、select から制約を外すとtask.order_id == 2問題が発生しなくなるので、トランザクションが開始されてから変更されたフィールドに基づいてクエリを実行することと関係があると思いますが、理由はわかりませんエラーメッセージは、別のトランザクションによって変更されたことを示していますdb.execute(生のSQLであるために別のトランザクションで実行されている可能性がある場合を除きますか?)

私はすでにこの同様の質問を見てきましたが、問題は異なっていました (ポニー ORM レポート レコードは「現在のトランザクションの外部で更新されました」が、他のトランザクションはありません) およびこのドキュメント ( https://docs.ponyorm.com/ transactions.html ) しかし、どちらも私の問題を解決しませんでした。

ここで何が起こっているのでしょうか?

4

1 に答える 1

3

Pony はデフォルトで楽観的同時実行制御を使用します。各属性について、Pony は現在の値 (アプリケーション コードによって変更される可能性があります) と、データベースから読み取られた元の値を記憶します。UPDATE 中、Pony はデータベース内の列の値が同じであることを確認します。値が変更された場合、Pony はいくつかの同時トランザクションがそれを行ったと想定し、「失われた更新」の状況を回避するために例外をスローします。

生の SQL クエリを実行すると、Pony はデータベースで何が変更されたかを正確に知りません。そのため、Pony がカウンター値が変更されたことに遭遇すると、値が別のトランザクションによって変更されたと誤って認識します。

この問題を回避するために、order_id属性を としてマークできますvolatile。次に、Pony は、属性の値が (トリガーまたは生の 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)

Pony はvolatile属性の値をキャッシュし、オブジェクトが保存されるまでデータベースから値を再読み込みしないことに注意してください。

アップデート:

リリース 0.7.4 以降では、生の SQL クエリを使用する特定のトランザクションのオプティミスティック チェックをオフにするoptimistic=Falseオプションを指定することもできます。db_session

with db_session(optimistic=False):
    ...

また

@db_session(optimistic=False)
def some_function():
    ...

またoptimistic=False、属性に を指定する代わりにオプションを指定できるようになりましvolatile=Trueた。その場合、Pony はその属性に対して楽観的なチェックを行いませんが、それでもそれを非揮発性として扱うことを検討します

于 2016-11-29T19:32:26.527 に答える