2015-11-18 149 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