MySQLdb.cursor.execute无法运行多个查询

l0b*_*0b0 14 python mysql mysql-python

我们尝试将包含多个插入语句的SQL文件作为单个查询运行,但是rollback当任何语句包含错误时,它似乎都失败了.

MySQLd配置:

sql_mode = STRICT_ALL_TABLES
default-storage-engine = innodb
Run Code Online (Sandbox Code Playgroud)

Python代码:

from contextlib import closing
import MySQLdb
database_connection = MySQLdb.connect(host="127.0.0.1", user="root")
with closing(database_connection.cursor()) as cursor:
    database_connection.begin()
    cursor.execute('DROP DATABASE IF EXISTS db_name')
    cursor.execute('CREATE DATABASE db_name')
    cursor.execute('USE db_name')
    cursor.execute('CREATE TABLE table_name(first_field INTEGER)')
with closing(database_connection.cursor()) as cursor:
    try:
        database_connection.begin()
        cursor.execute('USE db_name')
        cursor.execute('INSERT INTO table_name VALUES (1)')
        cursor.execute('INSERT INTO table_name VALUES ("non-integer value")')
        database_connection.commit()
    except Exception as error:
        print("Exception thrown: {0}".format(error))
        database_connection.rollback()
        print("Rolled back")
with closing(database_connection.cursor()) as cursor:
    try:
        database_connection.begin()
        cursor.execute('USE db_name')
        cursor.execute('INSERT INTO table_name VALUES (1); INSERT INTO table_name VALUES ("non-integer value")')
        database_connection.commit()
    except:
        print("Exception thrown: {0}".format(error))
        database_connection.rollback()
        print("Rolled back")
Run Code Online (Sandbox Code Playgroud)

预期结果:"抛出异常"和"回滚"两次打印.

MySQL-python 1.2.4的实际结果:

Exception thrown: (1366, "Incorrect integer value: 'non-integer value' for column 'first_field' at row 1")
Rolled back
Exception thrown: (1366, "Incorrect integer value: 'non-integer value' for column 'first_field' at row 1")
Traceback (most recent call last):
  File "test.py", line 30, in <module>
    print("Rolled back")
  File ".../python-2.7/lib/python2.7/contextlib.py", line 154, in __exit__
    self.thing.close()
  File ".../virtualenv-python-2.7/lib/python2.7/site-packages/MySQLdb/cursors.py", line 100, in close
    while self.nextset(): pass
  File ".../virtualenv-python-2.7/lib/python2.7/site-packages/MySQLdb/cursors.py", line 132, in nextset
    nr = db.next_result()
_mysql_exceptions.OperationalError: (1366, "Incorrect integer value: 'non-integer value' for column 'first_field' at row 1")
Run Code Online (Sandbox Code Playgroud)

是什么赋予了?我们是否真的必须解析SQL以拆分语句(包含所有需要的转义和引用处理)以在多个executes中运行它们?

Mar*_*ers 15

与所有Python DB-API 2.0实现一样,该cursor.execute()方法只需要一个语句,因为它可以保证游标的状态.

请改用该cursor.executemany()方法.请注意,根据DB-API 2.0规范:

将此方法用于生成一个或多个结果集的操作构成未定义的行为,并且当检测到通过调用操作创建了结果集时,允许(但不是必需)实现引发异常.

将它用于多个INSERT语句应该没问题:

cursor.executemany('INSERT INTO table_name VALUES (%s)',
    [(1,), ("non-integer value",)]
)
Run Code Online (Sandbox Code Playgroud)

如果您需要从脚本执行一系列不同的语句,那么在大多数情况下,您只需将语句拆分;并将每个语句cursor.execute()分别提供给它们.