SQLAlchemy 如何跟踪数据库更改?

Posted

技术标签:

【中文标题】SQLAlchemy 如何跟踪数据库更改?【英文标题】:How does SQLAlchemy track database changes? 【发布时间】:2015-11-18 17:19:57 【问题描述】:

我想知道 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)

【问题讨论】:

【参考方案1】:

会话的“缓存”是其 identity_map (session.identity_map.dict) 中的一个字典,它仅在“单个业务事务”期间缓存对象,如https://***.com/a/5869795 此处所回答。

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

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

因此,对于您的问题,如果您没有在 same 服务器请求中对 same object 进行查询,则无需在查询之前执行 session.commit()

希望对你有帮助。

【讨论】:

"记录保存在身份映射中以用于单个业务事务。这意味着无论您的 Web 服务器如何配置,您可能不会将它们保存超过请求(或将它们存储在会议)。”引用自***.com/questions/5869514/…

以上是关于SQLAlchemy 如何跟踪数据库更改?的主要内容,如果未能解决你的问题,请参考以下文章

flask mysql sqlalchemy教程

如何在 SQLAlchemy 中删除外键约束?

sqlalchemy.exc.NoSuchModuleError:无法加载插件:sqlalchemy.dialects:postgres

使用 Flask-SQLAlchemy 在 Alembic 自动生成迁移中未检测到任何变化

sqlalchemy 映射的小例子

Python 学习笔记 - SQLAlchemy(下)