为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

喵喵时光机 2023-10-11 15:36:44
我发现调用 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 对象上也不存在。关于如何执行此操作有什么建议吗?
查看完整描述

1 回答

?
慕后森

TA贡献1802条经验 获得超5个赞

据我所知,SQLAlchemy不支持直接调用存储过程。文档建议使用原始 DB-API 连接的callproc方法。

可以从引擎访问该连接;也可以通过会话访问它,但这仍然是通过引擎进行的。

下面的示例代码显示了这两种方法。请注意,访问调用过程结果的方法可能会有所不同,具体取决于所使用的参数和连接器 。

import mysql.connector


import sqlalchemy as sa

from sqlalchemy import orm


# Setup the database


DATA = [(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 procedure


engine = 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())

最后一个观察:在我看来,通过会话访问的原始连接位于会话的事务上下文之外,因此使用会话所做的更改可能对使用连接所做的更改不可见,具体取决于事务隔离设置。


查看完整回答
反对 回复 2023-10-11
  • 1 回答
  • 0 关注
  • 96 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信