Принудительное использование sqlalchemy ORM get() вне карты идентификации

Фон

get() Метод является особенным в ORM SQLAlchemy, потому что он пытается вернуть объекты из карты идентификаторов, прежде чем отправлять SQL-запрос к базе данных (см. документацию).

Это очень важно для производительности, но может вызвать проблемы для распределенных приложений, поскольку объект мог быть изменен другим процессом, поэтому локальный процесс не может знать, что объект загрязнен, и будет продолжать извлекать устаревший объект из карты идентификации, когда get() называется.


Вопрос

Как я могу заставить get() игнорировать карту идентификации и каждый раз вызывать БД?


пример

  • у меня есть Company объект, определенный в ORM.
  • у меня есть price_updater() процесс, который обновляет stock_price атрибут всех Company объекты каждую секунду.
  • у меня есть buy_and_sell_stock() процесс, который покупает и продает акции время от времени.
    • Теперь, внутри этого процесса, я мог загрузить microsoft = Company.query.get(123) объект.
    • Через несколько минут я могу позвонить еще раз Company.query.get(123), Цена акций изменилась с тех пор, но мой buy_and_sell_stock() процесс не знает об изменении, потому что это произошло в другом процессе.
    • Таким образом get(123) вызов возвращает устаревшую версию Company из карты идентификации сессии, которая является проблемой.

Я выполнил поиск по SO(под тегом [sqlalchemy]) и прочитал документацию по SQLAlchemy, чтобы попытаться выяснить, как это сделать, но не нашел способа.

1 ответ

Решение

С помощью session.expire(my_instance)приведет к повторному выбору данных при доступе. Тем не менее, даже если вы используетеexpire(или жеexpunge), следующие выбранные данные будут основаны на уровне изоляции транзакции. См. Документы PostgreSQL по уровням изоляции(это относится и к другим базам данных) и документацию по SQLAlchemy по настройке уровней изоляции.

Вы можете проверить, находится ли экземпляр в сеансе сin:my_instance in session,

Вы можете использоватьfilter вместоget обойти кеш, но он по-прежнему имеет такое же ограничение уровня изоляции.

Company.query.filter_by(id=123).one()
Другие вопросы по тегам