2015-11-18 203 views
8

我想知道SQLAlchemy如何跟踪在SQLAlchemy之外进行的更改(例如手动更改)?SQLAlchemy如何跟踪数据库更改?

到现在为止,我曾经把db.session.commit()放在每个可以在SQLAlchemy之外更改的值之前。这是一种不好的做法吗?如果是的话,有没有更好的方法来确保我有最新的价值?我实际上已经在下面创建了一个小脚本来检查它,显然,SQLAlchemy可以检测到外部更改,而不会每次调用db.session.commit()

感谢,

P.S:我真的想了解所有的魔法是如何发生的背后SQLAlchemy的工作。有没有人有指向一些文档解释SQLAlchemy的幕后工作?

import os 

from flask import Flask 
from flask_sqlalchemy import SQLAlchemy 

app = Flask(__name__) 

# Use SQLlite so this example can be run anywhere. 
# On Mysql, the same behaviour is observed 
basedir = os.path.abspath(os.path.dirname(__file__)) 
db_path = os.path.join(basedir, "app.db") 
app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///' + db_path 
db = SQLAlchemy(app) 


# A small class to use in the test 
class User(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(100)) 


# Create all the tables and a fake data 
db.create_all() 
user = User(name="old name") 
db.session.add(user) 
db.session.commit() 


@app.route('/') 
def index(): 
    """The scenario: the first request returns "old name" as expected. 
    Then, I modify the name of User:1 to "new name" directly on the database. 
    On the next request, "new name" will be returned. 
    My question is: how SQLAlchemy knows that the value has been changed? 
    """ 

    # Before, I always use db.session.commit() 
    # to make sure that the latest value is fetched. 
    # Without db.session.commit(), 
    # SQLAlchemy still can track change made on User.name 
    # print "refresh db" 
    # db.session.commit() 

    u = User.query.filter_by(id=1).first() 
    return u.name 


app.run(debug=True) 
+0

SQLAlchemy文档非常非常详尽,并提及外部资源。您是否考虑阅读这些内容以了解其工作原理? – davidism

+0

另外,还不清楚你发布的代码有什么问题。请[编辑]在帖子本身中创建描述您的问题的[mcve] *。 – davidism

+0

嘿感谢您的反馈。我试图在SQLAlchemy doc中搜索,但没有找到描述这个“魔术”背后的机制的部分。也许这是很多ORM使用的技术,所以SQLAlchemy不需要指出它? – Son

回答

4

该会话的“缓存”是在其identity_map(session.identity_map.dict),只有这里https://stackoverflow.com/a/5869795回答缓存对象为“单业务交易”的时候,一个字典。

对于不同的服务器请求,您有不同的identity_map。它不是共享对象。

在您的方案中,您请求了服务器2分开的时间。第二次,identity_map是一个新的(你可以通过打印出它的指针来轻松检查它),并且在缓存中没有任何内容。因此,会话将请求数据库并为您提供最新的答案。它不像你想象的那样“跟踪变化”。

所以,你的问题,你不需要查询之前做session.commit()如果你还没有在同一台服务器的请求做了查询的同一对象

希望它有帮助。

+0

“记录保存在单一业务事务的身份映射中,这意味着无论您的Web服务器如何配置,您可能都不会持有它们的时间超过请求(或将它们存储在会话中)。”引用来自http://stackoverflow.com/questions/5869514/sqlalchemy-identity-map-question/5869795#5869795 – Son