使用全局数据库实例的Flask-SQLAlchemy

时间:2015-03-10 11:45:52

标签: python flask sqlalchemy flask-sqlalchemy

这是我做的:

    from flask import Flask
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker

    dbhost = 'localhost'
    dbuser = 'user'
    dbpass = 'password'
    dbname = 'db'
    DBUri = 'mysql://%s:%s@%s/%s?charset=utf8'%(dbuser,dbpass,dbhost,dbname)

    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = (DBUri)
    app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'


    # an Engine, which the Session will use for connection
    # resources
    engine = create_engine(DBUri)

    # create a configured "Session" class
    Session = sessionmaker(bind=engine)

    # create a Session
    DBsession = Session()

@sched.cron_schedule(second='*/5')
def some_decorated_task():
    date_now = datetime.datetime.now().date()
    for item in DBsession.query(user_groups_n_hosts).filter(user_groups_n_hosts.end_time < str(date_now)): 
        print item.id, item.server_users.native_linux_user

有一个表 user_groups_n_hosts 上面的代码是一个每30秒运行一次的函数。

我的问题是,如果 user_groups_n_hosts 有10条记录,那么当我启动Flask应用程序时,无论在表格中插入多少条记录,上述代码都将继续打印10条记录<来自外部的strong> user_groups_n_hosts 。换句话说,我认为我的函数有一些表的实例,它只在应用程序初始化时初始化。 我知道我做的事情很愚蠢。请有人指出来。

取代DBsession.query(user_groups_n_hosts).filter(user_groups_n_hosts.end_time < str(date_now)): 我试过user_groups_n_hosts.query.filter(user_groups_n_hosts.end_time < str(date_now)): 但结果是一样的。

2 个答案:

答案 0 :(得分:1)

您的过滤器user_groups_n_hosts.end_time&lt; str(date_now)将日期与字符串进行比较。

此外,您应该将会话视为按请求进行操作,而不是整个应用中的持久实体。

考虑到这一点,请尝试更改

@sched.cron_schedule(second='*/5')
def some_decorated_task():
    date_now = datetime.datetime.now().date()
    for item in DBsession.query(user_groups_n_hosts).filter(user_groups_n_hosts.end_time < str(date_now)): 
        print item.id, item.server_users.native_linux_user

@sched.cron_schedule(second='*/5')
def some_decorated_task():
    date_now = datetime.datetime.now().date()
    sess = Session()
    for item in sess.query(user_groups_n_hosts).filter(user_groups_n_hosts.end_time < str(date_now)): 
        print item.id, item.server_users.native_linux_user
    sess.close()

答案 1 :(得分:1)

您每次都需要建立一个新的交易。 您可以在每次运行时创建一个全新的会话对象,重新使用会话,但在查询后确保commit()rollback()close()

这种影响是由MySQL的一些默认策略引起的。

如果您使用InnoDB作为MySQL的默认存储引擎,则它使用REPEATABLE READ作为其隔离级别。这是默认值,因为在大多数情况下,避免事务内部Non-repeatable Reads是有意义的。 因此,如果您没有结束交易,您每次都会从数据库中获得相同的结果。

来自SQLAlchemy docs

  

会话无论何时用于与数据库通信,都会在开始通信时立即开始数据库事务。假设autocommit标志保持其建议的默认值False,则此事务将继续进行,直到会话回滚,提交或关闭。如果在先前的交易结束之后再次使用会话,则会话将开始新的交易;由此得出,会话能够在许多交易中具有生命周期,尽管一次只能有一个交易。我们将这两个概念称为交易范围会话范围

另一个选项不推荐,正在使用autocommit=True创建会话,该会话将在每个查询语句之后自动提交事务。