Разъяснение возможности аномального обновления в транзакциях SQLAlchemy - PullRequest
0 голосов
/ 07 августа 2020

Указан код SQLAlchemy в следующем шаблоне:

def update_quantity(id, quantity):
    try:
        created = MyTable(id=id, quantity=quantity)
        session.add(created)
        session.commit()
    except sqlalchemy.exc.IntegrityError:
        session.rollback()
        try:
            record = MyTable.query.filter(MyTable.id=id).one()
            record.quantity = record.quantity + quantity
            session.commit()
        except sqlalchemy.orm.exc.NoResultFound:
            session.rollback()
            update_quantity(id, quantity)
    finally:
        session.close()

, где база данных - MySQL, autocommit = False, а уровень изоляции установлен на REPEATABLE READ.

С в отношении предотвращения обновления количества двумя параллельными процессами несогласованным образом (например, один с устаревшим значением количества),

  1. Не является повторяемым Чтение, достаточное для предотвращения такого рода аномалии обновления (т.е. он уже не прошел одну из попыток обновления?)
  2. Если это так, есть ли причина использовать (или избегать использования) FOR UPDATE в запросе записи, т.е. record = MyTable.query.filter(MyTable.id=id).for_update().one()? Не будет ли принудительно откат другого обновления в любом случае?
  3. Я специально использовал record.quantity = record.quantity + quantity, чтобы вызвать проблему с устаревшим обновлением; но если бы я сделал вместо этого record.quantity = MyTable.quantity + quantity - что, я думаю, переводится как UPDATE my_table SET quantity = quantity + %d WHERE id = %d и должно быть atomi c - можно ли вообще избежать всего состояния гонки?
...