V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
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 · 2017-01-21 05:39:34 +08:00 · 4663 次点击
    这是一个创建于 2868 天前的主题,其中的信息可能已经有所发展或是发生改变。
    创建了一个 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
    >>>
    第 1 条附言  ·  2017-01-22 21:16:23 +08:00
    很多人是没 get 到我的点, 还是觉得用的人多的库, 设计上就是十全十美无可指摘?
    大家觉得一个查询操作背后可以修改数据库, 这样的动作还合理的话, 可以看看这个帖子, 楼主在做类似的事情: https://www.v2ex.com/t/336226?p=1

    无论如何, 执行一个 query 操作, 这个动作就应该对数据库只读, 需要刷新的话, 可以挪到其他操作中去.
    8 条回复    2017-01-22 17:51:57 +08:00
    halmstad
        1
    halmstad  
       2017-01-21 07:53:31 +08:00 via iPhone   ❤️ 1
    首先,并没有提交到数据库,只 flush 了, flush 和 commit 不是一件事情。其次 session 创建的时候有个 auto_flush 参数表明 query 的时候是否 flush ,默认是 True, 多看看文档,才能更好的使用
    panyanyany
        2
    panyanyany  
       2017-01-21 08:03:17 +08:00
    在 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  
       2017-01-21 08:11:40 +08:00
    处理是合理的,只是不太智能,对同一个对象会生成多条更新语句.性能敏感时建议直接用 sql expression
    rogwan
        4
    rogwan  
       2017-01-21 08:26:36 +08:00
    和 return 返回自动提交类似,也算是一种防止用户忘记 commit 的做法吧。

    默认主动帮用户提交、默认不主动帮用户提交,两个方案肯定是选前者。
    eyp82
        5
    eyp82  
    OP
       2017-01-21 08:34:02 +08:00
    @halmstad 是没有 commit, 毕竟后面还可以 rollback. 我的意思是确实执行了写操作, 否则那个 auto_increment 的 id 是拿不到的(这个必须数据库生成并返回, ORM 不能自作主张生成一个) 而这个放在 query 里做, 感觉不如放到前面 add 里.
    eyp82
        6
    eyp82  
    OP
       2017-01-21 08:34:56 +08:00
    @halmstad 又看了一下我的帖子, 可能是我的标题有些误导.
    skydiver
        7
    skydiver  
       2017-01-21 13:28:29 +08:00 via Android
    正常行为,要不然你后面需要用这个 id 怎么办
    sleshep
        8
    sleshep  
       2017-01-22 17:51:57 +08:00
    一般中间 query 的时候都会手动 flush,这是常识
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4036 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 00:57 · PVG 08:57 · LAX 16:57 · JFK 19:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.