如何在sqlalchemy范围内的会话中执行MySQL存储过程以返回单个数据集(用于flask Web应用程序)?

摩奇

我发现的大多数调用MySQL存储proc并将结果存储在python中的示例都使用callproc带有方法cursor,但是该callproc方法scoped_session在使用sqlalchemy创建对象上不存在我使用a是scoped_session因为我正在构建一个烧瓶应用程序,该应用程序将在应用程序的不同部分中使用该会话(作用域会话适用于简单的select语句)。存储过程进行一次选择并返回数据。我正在使用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参数,因此即使存储的proc仅在运行单个选择查询,默认情况下它仍认为它是多语句。上的execute方法DbSession不接受选项。

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

有关如何执行此操作的任何建议?

蛇魅

据我所知,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())

最后一项观察:在我看来,通过会话访问的原始连接在会话的事务上下文之外,因此,根据事务隔离设置,使用会话进行的更改可能看不到使用连接进行的更改。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章