如何在 sqlalchemy 范围会话中执行 MySQL 存储过程以返回单个数据结果集

我发现调用 MySQL 存储过程并在 python 中存储结果的大多数示例都使用callproc带有 a 的方法cursor,但该callproc方法不存在于scoped_session使用 sqlalchemy 创建的对象上。我使用 a 是scoped_session因为我正在构建一个 Flask 应用程序,它将在应用程序的不同部分使用会话(作用域会话适用于简单的选择语句)。存储过程进行一项选择并返回数据。我正在使用 mysql.connector 作为 mysql 驱动程序。


我在烧瓶路线中尝试了以下方法,但出现错误:


mysql_engine = create_engine(conn_string)

DbSession = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=mysql_engine))


@app.route('/')

def index():

    # register session

    DbSession()


    sql = 'call myStoredProc(:param);'


    # call stored procedure: getting error "Use multi=True when executing multiple statements"

    result = DbSession.execute(sql, {'param': 'param value'})

    data = [dict(r) for r in result]


    # remove session from register

    DbSession.remove()


    # pass data to template to render

    return render_template('index.html', data = data)

如代码所示,我收到此错误:“执行多个语句时使用 multi=True。” 我了解到 mysq.connector 假设存储过程有一个 out 参数,因此默认情况下认为它是多语句,即使存储过程只是运行单个选择查询。execute的方法不DbSession接受选项。


错误中的建议是使用cmd_query_iter多个语句,但这在 DbSession 对象上也不存在。


关于如何执行此操作有什么建议吗?


喵喵时光机
浏览 106回答 1
1回答

慕后森

据我所知,SQLAlchemy不支持直接调用存储过程。文档建议使用原始 DB-API 连接的callproc方法。可以从引擎访问该连接;也可以通过会话访问它,但这仍然是通过引擎进行的。下面的示例代码显示了这两种方法。请注意,访问调用过程结果的方法可能会有所不同,具体取决于所使用的参数和连接器 。import mysql.connectorimport sqlalchemy as safrom sqlalchemy import orm# Setup the databaseDATA = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]DDL1 = """\CREATE TABLE IF NOT EXISTS test_table (  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,  a INT,  b INT,  c INT)"""DDL2 = """\CREATE PROCEDURE IF NOT EXISTS test_procedure (IN p1 INT)  BEGIN    SELECT a, b, c FROM test_table    WHERE a > p1;  END"""DML1 = """DELETE FROM test_table"""DML2 = """INSERT INTO test_table (a, b, c) VALUES (%s, %s, %s)"""CALL1 = """CALL test_procedure(:param)"""conn = mysql.connector.connect(database='test')cur = conn.cursor()cur.execute(DDL1)cur.execute(DDL2)cur.execute(DML1)for row in DATA:    cur.execute(DML2, row)conn.commit()conn.close()# Call the procedureengine = sa.create_engine('mysql+mysqlconnector:///test')Session = orm.scoped_session(orm.sessionmaker(autocommit=False, autoflush=False, bind=engine))session = Session()raw_conn = session.connection().engine.raw_connection()cur = raw_conn.cursor()cur.callproc('test_procedure', [1])print('Using session')for result in cur.stored_results():    print(result.fetchall())Session.remove()print('Using engine directly')raw_conn = engine.raw_connection()cur = raw_conn.cursor()cur.callproc('test_procedure', [1])for result in cur.stored_results():    print(result.fetchall())最后一个观察:在我看来,通过会话访问的原始连接位于会话的事务上下文之外,因此使用会话所做的更改可能对使用连接所做的更改不可见,具体取决于事务隔离设置。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python