2012-04-18 145 views
12

我在使用sqlalchemy时遇到缓存问题。我使用sqlalchemy将数据插入到mysql数据库中。我有另一个应用程序处理这些数据,然后直接更新这些数据。但我的sqlalchemy总是得到旧数据,而不是更新的数据..我认为sqlalchemy缓存我的请求..所以..如何禁用它?如何禁用SQLAlchemy缓存?

+1

相关? http://stackoverflow.com/questions/16586114/sqlalchemy-returns-stale-rows – 2013-05-16 11:21:50

回答

34

通常引起人的思维有一个“缓存”在作怪,除了一般的SQLAlchemy的身份地图是本地的事务,是他们正在观察事务隔离的效果。默认情况下,SQLAlchemy的会话在事务模式下工作,这意味着它会等到调用session.commit()才能将数据保存到数据库。在此期间,别处正在进行的其他交易将不会看到这些数据。

然而,由于交易的性质孤立,有一个额外的扭曲。在进展的其他交易不仅不会看到您的交易数据,直到它承诺,他们也无法看到它在某些情况下,直到他们提交或回滚也(这是一样的效果您close()时有这里)。平均程度的隔离事务将保留状态,它迄今加载,并不断给你同样的状态本地尽管实际数据已经改变了交易 - 这被称为重复的事务读取隔离的说法。

http://en.wikipedia.org/wiki/Isolation_%28database_systems%29

-1

据我所知SQLAlchemy的does not store caches,所以你需要寻找logging输出。

+0

我这么认为。我打开'echo = True',但没有任何用处。 – 2012-04-18 13:31:04

+0

你有提交更新会话吗? – 2012-04-18 13:38:12

+0

我更新数据而不使用sqlalchemy ..使用'MySQLdb' ..我确保数据已经在MySQL中更新了.. – 2012-04-18 13:40:25

0

首先,SQLAlchemy没有缓存。 根据您从DB获取数据的方法,您应该在数据库被其他人更新后进行一些测试,看看您是否可以获取新数据。

(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... 

请如下因素在步:http://docs.sqlalchemy.org/en/latest/core/connections.html

另一个可能的原因是你的MySQL数据库没有更新永久。重新启动MySQL服务并进行检查。

+0

感谢您的回复。我解决了它。当我使用'scoped_session'时,我忘了'session.close' ... – 2012-04-18 14:11:48

3

此外,以zzzeek出色答卷,

我有一个类似的问题。我通过短暂的生活会议解决了这个问题。

with closing(new_session()) as sess: 
    # do your stuff 

我使用了每个任务,任务组或请求的新会话(以web应用程序为例)。这解决了我的“缓存”问题。

这种材料对我来说非常有用

When do I construct a Session, when do I commit it, and when do I close it

+1

上面的链接是去会话的文档。标题意味着它应该指向这里:http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#session-faq-whentocreate – mozey 2015-05-29 09:13:24

11

这个问题对我来说真的很令人沮丧,但我终于想通了。

我旁边有一个较旧的PHP网站上投放的瓶/ SQLAlchemy的应用。 PHP站点会写入数据库,SQLAlchemy不会意识到任何更改。

我试过sessionmaker设置autoflush = True失败 在查询和NONE工作之前,我尝试了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:[email protected]/test", 
       isolation_level="READ UNCOMMITTED" 
      ) 

当SQLAlchemy的发动机起动“读UNCOMMITED” ISOLATION_LEVEL它将执行“脏读”,这意味着它会直接从数据库中读取未提交更改。

希望这有助于


这是在评论

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) 
+0

如果你正在使用Flask-SQLAlchemy,你可以继承'flask.ext .sqlalchemy.SQLAlchemy'并覆盖'apply_driver_hacks'函数来设置隔离级别,同时仍然保留所有Flask集成。此外,可能隔离级别“READ COMMITTED”足以让两个应用程序在创建它们之后提交它们的写入,而不是等待很长时间。这样,您就不必担心脏读 - 每次阅读时它都会为您提供全新的数据库快照。 – 2015-09-16 05:09:18

+0

@AaronD你可以将你的代码发布到子类'flask.ext.sqlalchemy.SQLAlchemy'吗? – 2016-03-08 20:05:11

+1

我只是有这个在我的代码: '类UnlockedAlchemy(SQLAlchemy的): 高清apply_driver_hacks(个体经营,应用,信息,选项): 如果没有 “ISOLATION_LEVEL” 的选项: 选项[ “ISOLATION_LEVEL”] =“READ COMMITTED “ return super(UnlockedAlchemy,self).apply_driver_hacks(app,info,options)' – 2016-03-09 14:33:59

3

这是在我的瓶的应用程序发生AaronD的可能的解决方案礼貌,我的解决办法是过期的所有对象每次请求后会话。

from flask.signals import request_finished 
def expire_session(sender, response, **extra): 
    app.db.session.expire_all() 
request_finished.connect(expire_session, flask_app) 

工作就像一个魅力。