SQL炼金术:了解expire_on_commit

时间:2018-07-13 10:57:00

标签: python sqlalchemy

我试图了解Session的{​​{3}}参数的行为。

因此,我创建了一个小程序,其中添加了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)

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

expire_on_commitFalse时的输出:

...
=== access a user ===
u2

到目前为止,这符合我的预期:对于expire_on_commit,提交后的下一次访问将发出SQL查询,而当expire_on_commit关闭时,则没有SQL查询。

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

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

u1.name = "new name"

我使用update更新了所有用户:

session.query(User).update({'name': "new name"})

输出:

...
=== access a user ===
new name

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

1 个答案:

答案 0 :(得分:2)

根据文档,Query.update()参数synchronize_session的默认值为'evaluate'

  

直接在Python中的对象上评估Python中的查询条件   会议。

如果您这样拨打update()

session.query(User).update({'name': "new name"}, synchronize_session=False)

尽管数据库已更改,但会话中的对象将保持不变:

...
=== access a user ===
u2