试图让Storm ORM与Pyramid配合,但线程出现问题

0 投票
2 回答
723 浏览
提问于 2025-04-16 21:39

这是我网站上 __init__.py 文件中的相关代码

from site.models import initialise_sql

def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application """

    initialise_sql(settings['database.url'])

    return config.make_wsgi_app()

这是我的 models/__init__.py 文件

from storm.locals import *

from datetime import datetime

DBSession = None

class Tables:
    """ A simple namespace for all the table objects in our database """

    class Users(object):

        __storm_table__ = 'users'

        user_id      = Int(primary=True)
        username     = RawStr()
        password     = RawStr()
        date_created = DateTime(default=datetime.now())

def initialise_sql(db_uri):
    """ Initialise the database """

    global DBSession

    database  = create_database(db_uri)
    DBSession = Store(database)

还有这是我的用户模型:

def create_account(username, password):

    user = Tables.Users()
    user.username = username
    user.password = password

    DBSession.add(user)
    DBSession.flush()

根据我阅读的Storm文档,这些代码都是正确的。问题是,当我从视图调用中调用 create_account 函数时,出现了以下异常:

ProgrammingError: SQLite objects created in a thread can only be used in that same thread.The object was created in thread id -1220417856 and this is thread id -1239418000

我甚至不知道Pyramid在处理多线程应用程序 :/

我该如何解决这个问题呢?

2 个回答

0
global DBSession

这是你的问题。Storm的手册对此有很清楚的说明,详细内容可以查看这里

你需要使用线程本地存储。使用threading.local就是解决办法:

import threading
tlocal = threading.local()

def initialise_sql(db_uri):
    global tlocal
    db = create_database(db_uri)
    tlocal.dbsession = Store(db)

#etc
1

你使用的网络服务器是多线程的,而不是Pyramid本身。想想你的应用程序是如何处理请求的,这样更安全。简单来说,在任何时刻,每个线程会处理一个请求,所以每个活跃的请求应该使用不同的数据库连接。使用SQLAlchemy的scoped_session可以很简单地做到这一点,不过你也可以像这个Pyramid教程那样,使用原始的SQLite连接来实现。

这里的基本思路是,在NewRequest的订阅者中建立一个新的数据库连接,这样就能确保在请求之间不会因为共享连接而出现线程问题。你也可以使用连接池的方式,我相信任何一个不错的ORM都会提供这个功能。

更新 在更仔细地查看Storm后,我发现它对连接池的支持并不多,但有一个ZStorm包可以将Storm与Pyramid使用的事务管理器集成。这个包实现了一些连接池机制,可以让你的工作更轻松。

撰写回答