SQL炼金术:了解expire_on_commit

Era*_*man 2 python sqlalchemy

我试图了解 的expire_on_commitSession参数的行为。

所以我创建了一个小程序,添加 2 行,更新其中一行,然后访问另一行:

engine = sa.create_engine('sqlite:///tmp.db', echo=True)
Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)

Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine, expire_on_commit=True)
session = Session()

# add 2 users
u1 = User(name="u1")
u2 = User(name="u2")
session.add(u1)
session.add(u2)
session.commit()

# update a user
u1.name = "new name"
session.commit()

print("=== access a user ===")
print(u2.name)
Run Code Online (Sandbox Code Playgroud)

输出时间expire_on_commitTrue(默认):

2018-07-13 13:38:14,478 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2018-07-13 13:38:14,478 INFO sqlalchemy.engine.base.Engine ()
2018-07-13 13:38:14,479 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2018-07-13 13:38:14,479 INFO sqlalchemy.engine.base.Engine ()
2018-07-13 13:38:14,479 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users")
2018-07-13 13:38:14,479 INFO sqlalchemy.engine.base.Engine ()
2018-07-13 13:38:14,480 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE users (
        id INTEGER NOT NULL, 
        name VARCHAR, 
        PRIMARY KEY (id)
)


2018-07-13 13:38:14,480 INFO sqlalchemy.engine.base.Engine ()
2018-07-13 13:38:14,488 INFO sqlalchemy.engine.base.Engine COMMIT
2018-07-13 13:38:14,490 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-07-13 13:38:14,491 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name) VALUES (?)
2018-07-13 13:38:14,491 INFO sqlalchemy.engine.base.Engine ('u1',)
2018-07-13 13:38:14,491 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name) VALUES (?)
2018-07-13 13:38:14,491 INFO sqlalchemy.engine.base.Engine ('u2',)
2018-07-13 13:38:14,492 INFO sqlalchemy.engine.base.Engine COMMIT
2018-07-13 13:38:14,497 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-07-13 13:38:14,497 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id 
FROM users 
WHERE users.id = ?
2018-07-13 13:38:14,497 INFO sqlalchemy.engine.base.Engine (1,)
2018-07-13 13:38:14,498 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ?
2018-07-13 13:38:14,498 INFO sqlalchemy.engine.base.Engine ('new name', 1)
2018-07-13 13:38:14,499 INFO sqlalchemy.engine.base.Engine COMMIT
=== access a user ===
2018-07-13 13:38:14,504 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-07-13 13:38:14,504 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name 
FROM users 
WHERE users.id = ?
2018-07-13 13:38:14,505 INFO sqlalchemy.engine.base.Engine (2,)
u2
Run Code Online (Sandbox Code Playgroud)

expire_on_commit时的输出False

...
=== access a user ===
u2
Run Code Online (Sandbox Code Playgroud)

到目前为止,正如我所期望的:使用 时expire_on_commit,提交后的下一次访问会发出 SQL 查询,而当expire_on_commit关闭时,没有 SQL 查询。

现在,我想创建一个示例,其中提交后的访问提供了过时的数据。

所以不要直接更新第一个用户

u1.name = "new name"
Run Code Online (Sandbox Code Playgroud)

我使用以下方式更新了所有用户update

session.query(User).update({'name': "new name"})
Run Code Online (Sandbox Code Playgroud)

输出:

...
=== access a user ===
new name
Run Code Online (Sandbox Code Playgroud)

没有 SQL 查询,但令人惊讶的是该值是正确的。我希望更新由数据库本身处理,因此缓存的对象不会意识到更改。我想念什么?

shm*_*mee 6

Query.update()参数的默认值synchronize_session的默认值是“evaluate”,根据文档:

\n\n
\n

直接在会话中的对象上评估 Python 中的 Query\xe2\x80\x99s 标准。

\n
\n\n

如果你打电话update()这样调用:

\n\n
session.query(User).update({\'name\': "new name"}, synchronize_session=False)\n
Run Code Online (Sandbox Code Playgroud)\n\n

尽管数据库发生变化,会话中的对象将保持不变:

\n\n
...\n=== access a user ===\nu2\n
Run Code Online (Sandbox Code Playgroud)\n