Принудительное использование 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()