推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
eyp82
V2EX  ›  Python

SQLAlchemy 的 session.query(...).all()居然会把还没 commit 的对象 flush 到数据库?

  •  
  •   eyp82 · Jan 21, 2017 · 5080 views
    This topic created in 3428 days ago, the information mentioned may be changed or developed.
    创建了一个 object, 以及把其加入到 session 里后, 查询 id 都是空, 但是执行了一次 query 之后 id 就有值了.

    感觉这么处理很怪, 一个 query 语句居然会背地里对数据库做修改. 不太理解为什么要这样设计. 我觉得把修改数据库的动作放到session.add()里不是更好? query我默认就是不对数据库做修改的啊.


    ----------
    解释一下下面的输出: User是一个类, 代表一张表, session是我创建的Session类的对象.
    1. 创建一行数据(User的实例)
    2. 调用session.add()加入到session
    3. 查询: session.query(...).all()

    ------------------------
    >>> user7 = User(name='test', fullname='test_full', password='nopwd')
    >>> user7.id
    >>> session.add(user7)
    >>> user7.id
    >>> session.query(User).all()
    2017-01-20 16:37:00,557 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
    2017-01-20 16:37:00,557 INFO sqlalchemy.engine.base.Engine ('test', 'test_full', 'nopwd')
    2017-01-20 16:37:00,557 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password
    FROM users
    2017-01-20 16:37:00,558 INFO sqlalchemy.engine.base.Engine ()
    [...deleted...]
    >>> user7.id
    8
    >>>
    Supplement 1  ·  Jan 22, 2017
    很多人是没 get 到我的点, 还是觉得用的人多的库, 设计上就是十全十美无可指摘?
    大家觉得一个查询操作背后可以修改数据库, 这样的动作还合理的话, 可以看看这个帖子, 楼主在做类似的事情: https://www.v2ex.com/t/336226?p=1

    无论如何, 执行一个 query 操作, 这个动作就应该对数据库只读, 需要刷新的话, 可以挪到其他操作中去.
    8 replies    2017-01-22 17:51:57 +08:00
    halmstad
        1
    halmstad  
       Jan 21, 2017 via iPhone   ❤️ 1
    首先,并没有提交到数据库,只 flush 了, flush 和 commit 不是一件事情。其次 session 创建的时候有个 auto_flush 参数表明 query 的时候是否 flush ,默认是 True, 多看看文档,才能更好的使用
    panyanyany
        2
    panyanyany  
       Jan 21, 2017
    在 SQLAlchemy 中, add() 操作之后数据成为 pending 状态,此时数据不会立即写入到数据库中。
    当你执行 query() 的时候,它会先把之前状态为 pending 的数据写入到数据库,并且更新当前 session 中存储的数据,然后再执行 query()
    你可以看下文档的这个小节:
    [Adding and Updating Objects]( http://docs.sqlalchemy.org/en/rel_1_1/orm/tutorial.html#adding-and-updating-objects)
    jjx
        3
    jjx  
       Jan 21, 2017
    处理是合理的,只是不太智能,对同一个对象会生成多条更新语句.性能敏感时建议直接用 sql expression
    rogwan
        4
    rogwan  
       Jan 21, 2017
    和 return 返回自动提交类似,也算是一种防止用户忘记 commit 的做法吧。

    默认主动帮用户提交、默认不主动帮用户提交,两个方案肯定是选前者。
    eyp82
        5
    eyp82  
    OP
       Jan 21, 2017
    @halmstad 是没有 commit, 毕竟后面还可以 rollback. 我的意思是确实执行了写操作, 否则那个 auto_increment 的 id 是拿不到的(这个必须数据库生成并返回, ORM 不能自作主张生成一个) 而这个放在 query 里做, 感觉不如放到前面 add 里.
    eyp82
        6
    eyp82  
    OP
       Jan 21, 2017
    @halmstad 又看了一下我的帖子, 可能是我的标题有些误导.
    skydiver
        7
    skydiver  
       Jan 21, 2017 via Android
    正常行为,要不然你后面需要用这个 id 怎么办
    sleshep
        8
    sleshep  
       Jan 22, 2017
    一般中间 query 的时候都会手动 flush,这是常识
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1100 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 18:33 · PVG 02:33 · LAX 11:33 · JFK 14:33
    ♥ Do have faith in what you're doing.