在使用 sqlalchemy
时,我遇到了缓存问题。
我使用 sqlalchemy
将数据插入 MySQL 数据库。然后,我有另一个应用程序处理这些数据,并对其进行直接更新。
但是,sqlalchemy
总是返回旧的数据而不是更新后的数据。我认为 sqlalchemy
缓存了我的请求,因此我该如何禁用它呢?
在使用 sqlalchemy
时,我遇到了缓存问题。
我使用 sqlalchemy
将数据插入 MySQL 数据库。然后,我有另一个应用程序处理这些数据,并对其进行直接更新。
但是,sqlalchemy
总是返回旧的数据而不是更新后的数据。我认为 sqlalchemy
缓存了我的请求,因此我该如何禁用它呢?
session.commit()
方法才将数据持久化到数据库中。在此期间,在其他地方正在进行的事务中,将无法看到此数据。这个问题一直让我很沮丧,但我终于解决了。
我有一个运行在旧 PHP 站点旁边的 Flask/SQLAlchemy 应用程序。PHP 站点会向数据库写入数据,而 SQLAlchemy 却不知道任何更改。
我尝试设置 sessionmaker 的 autoflush=True,但没有成功。 我尝试在查询之前使用 db_session.flush()、db_session.expire_all() 和 db_session.commit(),但都无效。仍然显示旧数据。
最后我找到了 SQLAlchemy 文档中的这一部分:http://docs.sqlalchemy.org/en/latest/dialects/postgresql.html#transaction-isolation-level
设置 isolation_level 很有效。现在我的 Flask 应用程序正在与 PHP 应用程序“通信”。以下是代码:
engine = create_engine(
"postgresql+pg8000://scott:tiger@localhost/test",
isolation_level="READ UNCOMMITTED"
)
当SQLAlchemy引擎使用"READ UNCOMMITTED"隔离级别启动时,它将执行"脏读取"操作,这意味着它将直接从数据库读取未提交的更改。
希望这可以帮助。
以下是评论区AaronD提供的可能解决方案:
from flask.ext.sqlalchemy import SQLAlchemy
class UnlockedAlchemy(SQLAlchemy):
def apply_driver_hacks(self, app, info, options):
if "isolation_level" not in options:
options["isolation_level"] = "READ COMMITTED"
return super(UnlockedAlchemy, self).apply_driver_hacks(app, info, options)
flask.ext.sqlalchemy.SQLAlchemy
并覆盖apply_driver_hacks
函数以设置隔离级别,同时仍保留所有Flask集成。此外,也许隔离级别READ COMMITTED
就足够了,只要两个应用程序在进行写入后立即提交而不是等待很长时间即可。这样,您就不必担心脏读问题-每次读取时它都会为您提供新的DB快照。 - Aaron Dflask.ext.sqlalchemy.SQLAlchemy
的代码? - Nick Woodhamsclass UnlockedAlchemy(SQLAlchemy):
def apply_driver_hacks(self, app, info, options):
if not "isolation_level" in options:
options["isolation_level"] = "READ COMMITTED"
return super(UnlockedAlchemy, self).apply_driver_hacks(app, info, options)
- Aaron Dengine_from_config
从文件中读取 sqlalchemy 配置,我只需在配置文件中添加:sqlalchemy.isolation_level = READ UNCOMMITTED
,现在外部更改已正确地反映在我的应用程序中 :-) - ozbob除了 zzzeek 的出色回答之外,
我也遇到了类似的问题。通过使用短生命周期的会话,我解决了这个问题。
with closing(new_session()) as sess:
# do your stuff
对于每个任务、任务组或请求(在 Web 应用程序的情况下)我使用一个新的会话。这解决了我的“缓存”问题。
这个材料对我来说非常有用:
from flask.signals import request_finished
def expire_session(sender, response, **extra):
app.db.session.expire_all()
request_finished.connect(expire_session, flask_app)
非常顺利地完成了。
我尝试过使用session.commit(), session.flush()
,但都没有成功。
在查看了sqlalchemy源代码后,我发现了禁用缓存的解决方法。
在create_engine
中设置query_cache_size=0
即可。
create_engine(connection_string, convert_unicode=True, echo=True, query_cache_size=0)
query_cache_size
控制 SQLAlchemy 的最近生成的 SQL 查询字符串的缓存大小。它对查询结果没有影响,除了可能使它们变慢。当然,它会影响内存使用。 - snakecharmerbimport sqlalchemy as db
db.create_engine(db_string, query_cache_size=0, pool_size=30, max_overflow=0, pool_pre_ping=True, echo=True, echo_pool=True)
首先,SQLAlchemy 没有缓存机制。 根据你从数据库获取数据的方法,在其他人更新数据库后,应该进行一些测试,看看是否可以获取新数据。
(1) use connection:
connection = engine.connect()
result = connection.execute("select username from users")
for row in result:
print "username:", row['username']
connection.close()
(2) use Engine ...
(3) use MegaData...
scoped_session
时,我只是忘记了session.close
... - Zeyi Fanecho = True
但是没有得到任何有用的东西。 - Zeyi FanMySQLdb
更新数据,而不使用SQLAlchemy。我确保数据已在MySQL中更新。 - Zeyi Fanscoped_session
时忘记了 session.close()
。有点糊涂。。 - Zeyi Fan