Резюме
Я пытаюсь написать интеграционные тесты для ряда операций с базами данных и хочу использовать сеанс SQLAlchemy в качестве промежуточной среды для проверки и отката транзакции.
Возможно ли получить незафиксированные данные, используя session.query(Foo)
вместо session.execute(text('select * from foo'))
?
Предпосылки и исследования
Эти результаты были получены с использованием SQLAlchemy 1.2.10, Python 2.7.13 и Postgres 9.6.11.
Я просмотрел соответствующие записи в StackOverflow, но не нашел объяснения, почему две нижеприведенные операции должны вести себя по-разному.
Воспроизводимый пример
1) Я устанавливаю соединение с базой данных и определяю объект модели; пока проблем нет:
from sqlalchemy import text
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
#####
# Prior DB setup:
# CREATE TABLE foo (id int PRIMARY KEY, label text);
#####
# from https://docs.sqlalchemy.org/en/13/orm/mapping_styles.html#declarative-mapping
Base = declarative_base()
class Foo(Base):
__tablename__ = 'foo'
id = Column(Integer, primary_key=True)
label = Column(String)
# from https://docs.sqlalchemy.org/en/13/orm/session_basics.html#getting-a-session
some_engine = create_engine('postgresql://username:password@endpoint/database')
Session = sessionmaker(bind=some_engine)
2) Я выполняю некоторые обновления, не фиксируя результат, и я могу увидеть промежуточные данные, выполнив оператор select в сеансе:
session = Session()
sql_insert = text("INSERT INTO foo (id, label) VALUES (1, 'original')")
session.execute(sql_insert);
sql_read = text("SELECT * FROM foo WHERE id = 1");
res = session.execute(sql_read).first()
print res.label
sql_update = text("UPDATE foo SET label = 'updated' WHERE id = 1")
session.execute(sql_update)
res2 = session.execute(sql_read).first()
print res2.label
sql_update2 = text("""
INSERT INTO foo (id, label) VALUES (1, 'second_update')
ON CONFLICT (id) DO UPDATE
SET (label) = (EXCLUDED.label)
""")
session.execute(sql_update2)
res3 = session.execute(sql_read).first()
print res3.label
session.rollback()
# prints expected values: 'original', 'updated', 'second_update'
3) Я пытаюсь заменить операторы select на session.query, но я не вижу новые данные:
session = Session()
sql_insert = text("INSERT INTO foo (id, label) VALUES (1, 'original')")
session.execute(sql_insert);
res = session.query(Foo).filter_by(id=1).first()
print res.label
sql_update = text("UPDATE foo SET label = 'updated' WHERE id = 1")
session.execute(sql_update)
res2 = session.query(Foo).filter_by(id=1).first()
print res2.label
sql_update2 = text("""
INSERT INTO foo (id, label) VALUES (1, 'second_update')
ON CONFLICT (id) DO UPDATE
SET (label) = (EXCLUDED.label)
""")
session.execute(sql_update2)
res3 = session.query(Foo).filter_by(id=1).first()
print res3.label
session.rollback()
# prints: 'original', 'original', 'original'
Я ожидаю, что напечатанный вывод шага 3 будет 'оригинальным', 'обновленным', 'second_update'.