首页 > 解决方案 > 我可以在没有事务的情况下通过 sqlalchemy 执行查询吗

问题描述

我正在尝试使用 sqlalchemy 在 Mysql 数据库上执行存储过程。

它在 shell 中运行良好,但抛出此错误:

OperationalError: (MySQLdb._exceptions.OperationalError) (1568, "Transaction characteristics can't be changed while a transaction is in progress")

原因似乎是 SQLAlchemy 在事务中运行查询。并且存储过程中的事务与之冲突。以下是 sqlalchemy 日志:

2019-07-24 15:20:28,888 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode'
2019-07-24 15:20:28,888 INFO sqlalchemy.engine.base.Engine ()
2019-07-24 15:20:28,900 INFO sqlalchemy.engine.base.Engine SELECT DATABASE()
2019-07-24 15:20:28,900 INFO sqlalchemy.engine.base.Engine ()
2019-07-24 15:20:28,910 INFO sqlalchemy.engine.base.Engine show collation where `Charset` = 'utf8mb4' and `Collation` = 'utf8mb4_bin'
2019-07-24 15:20:28,910 INFO sqlalchemy.engine.base.Engine ()
2019-07-24 15:20:28,916 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAR(60)) AS anon_1
2019-07-24 15:20:28,917 INFO sqlalchemy.engine.base.Engine ()
2019-07-24 15:20:28,923 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_1
2019-07-24 15:20:28,923 INFO sqlalchemy.engine.base.Engine ()
2019-07-24 15:20:28,928 INFO sqlalchemy.engine.base.Engine SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin AS anon_1
2019-07-24 15:20:28,928 INFO sqlalchemy.engine.base.Engine ()
2019-07-24 15:20:28,938 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-07-24 15:20:28,938 INFO sqlalchemy.engine.base.Engine CALL my_stored_procedure(params);
2019-07-24 15:20:28,938 INFO sqlalchemy.engine.base.Engine ()

我想知道的是我是否可以在没有事务的情况下从 sqlalchemy 运行查询。或者有没有其他方法可以解决问题。我尝试更改存储过程的隔离级别,但这会导致表锁定问题。

标签: pythonmysqlsqlalchemyflask-sqlalchemy

解决方案


SQLAlchemy 总是尝试在事务中执行查询。COMMIT但是,可以通过执行语句轻松结束事务。

首先,你需要一个连接。然后使用该连接发出一个COMMIT,这将结束新启动的事务。

这是一个尝试创建新数据库的示例代码,在事务内部运行时会引发错误。我正在使用 postgres,但使用 MySQL 的相同逻辑也适用。尝试在事务中创建新数据库:

from sqlalchemy import create_engine

# replace URL with your MySQL instance
db_url = "postgresql://postgres:secure_pass@localhost:5432/template1"
engine = create_engine(db_url)

connection = engine.connect()

# running this query in transaction throws an error
result = connection.execute("CREATE DATABASE temp_db")

会抛出错误:

ERROR: CREATE DATABASE cannot run inside a transaction block

现在,添加COMMIT将结束一个由 sqlalchemy 启动的事务:

from sqlalchemy import create_engine

# replace url with your MySQL instance
db_url = "postgresql://postgres:secure_pass@localhost:5432/template1"
engine = create_engine(db_url)

connection = engine.connect()

# commiting will end a transaction
connection.execute("COMMIT")

# now this query runs fine
result = connection.execute("CREATE DATABASE temp_db")

并且不会引发任何错误。


推荐阅读