Sqlalchemy在多个写线程上

时间:2017-12-07 02:55:28

标签: python python-3.x sqlalchemy python-multithreading

以下代码适用于Python 3.6+,而不适用于Python 3.4.3,不确定它失败的版本。为什么是这样?我的印象是,sqlalchemy可能会将多个读者/编写者处理为基于文件的数据库,可能是将其隐藏在调用的序列化器后面。无论如何,这表明我没有处理这个权利 - 如何在多个线程上插入,或者在主线程中插入一个线程,版本< 3.6

我在sqlalchemy session()sqlalchemy connection pool on multiple threads

尝试了此操作

但是只能让它与引擎一起使用,现在我只能在3.6上找到它。

def insert_inventory_table(conn, table, inventory):
    conn.execute(table.insert(), inventory)    

def results_table(conn, table):
    q = select([table])
    data = conn.execute(q).fetchall()
    print('{!r}'.format(data))


def main_0():
    engine = create_engine('sqlite://', connect_args={'check_same_thread' : False})
    conn = engine.connect()

    metadata = MetaData(engine)
    table = Table('inventory',
              metadata,
              Column('item_no', Integer, primary_key=True, autoincrement=True),
              Column('desc', String(255), nullable=False),
              Column('volume', Integer, nullable=False)
              )

    metadata.create_all()

    some_inventory = [{'item_no' : 0, 'desc' : 'drone', 'volume' : 12},
                      {'item_no' : 1, 'desc' : 'puddle jumper', 'volume' : 2},
                      {'item_no' : 2, 'desc' : 'pet monkey', 'volume' : 1},
                      {'item_no' : 3, 'desc' : 'bowling ball', 'volume' : 4},
                      {'item_no' : 4, 'desc' : 'electric guitar', 'volume' : 3},
                      {'item_no' : 5, 'desc' : 'bookends', 'volume' : 2}]


    thread_0 = threading.Thread(target=insert_inventory_table, args=(conn, table, some_inventory[0:3]))
    thread_1 = threading.Thread(target=insert_inventory_table, args=(conn, table, some_inventory[3:]))

    thread_0.start()
    thread_1.start()

    return conn, table


if __name__ == '__main__':

    conn,table = main_0()
    results_table(conn, table)

感谢。

2 个答案:

答案 0 :(得分:1)

正如所指出的,您必须使用作用域会话,因此要使用conn:

from sqlalchemy.orm import sessionmaker, scoped_session

db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))

然后每当您在线程中连接到数据库时,记住要打开和关闭会话,就不希望线程共享会话,因为这会导致不良后果,所以:

def worker(sth):
     session = db_session()
     "do sth very important"
     res = session.query(YourModel).filter(YourModel.sth = sth).first()
     print(res)
     session.close()

然后,您可以在多线程操作中使用此类工作程序。希望对您有所帮助。

答案 1 :(得分:0)

让我在上述答案中添加一些内容(因为我无法再对其进行编辑)。通过作用域范围内的会话,您可以调用与数据库连接的其他函数,并且不必将会话添加为这些函数的参数,因为在同一线程中创建的每个下一个会话都是相同的会话。所以:

def worker(sth):
     session = db_session()
     "do sth very important"
     res = session.query(YourModel).filter(YourModel.sth == sth).first()
     your_very_importan_function(sth)

     print(res)
     db_session.remove()

def your_very_important_function(sth):
     session = db_session()    # this session will be the same as the session created in the worker function, and in the worker function, it is different for every thread.
    "do sth even more important"
    res = session.query(YourOtherModel).filter(YourOtherModel.sth == sth).first()

最后,您应该删除会话,而不仅仅是关闭它。 https://docs.sqlalchemy.org/en/13/orm/contextual.html