[英]MySQLdb.cursor.execute can't run multiple queries
我們試圖將包含多個插入語句的 SQL 文件作為單個查詢運行,但是當任何語句包含錯誤時, rollback
似乎失敗。
MySQLd 配置:
sql_mode = STRICT_ALL_TABLES
default-storage-engine = innodb
蟒蛇代碼:
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")
預期結果:“拋出異常”和“回滾”打印兩次。
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")
什么給? 我們真的必須解析 SQL 來拆分語句(包括所有需要的轉義和引號處理)以在多個execute
運行它們嗎?
像所有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",)]
)
如果您需要從腳本中執行一系列不同的語句,那么在大多數情況下,您只需將語句拆分為;
並將每個語句分別提供給cursor.execute()
。
我認為您在使用多個語句時需要通過multi=True
來execute
,請參閱http://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html
更新:這適用於mysql.connector
模塊,而不是在這種情況下使用的MySQLdb
。
顯然是沒有辦法在做這個MySQLdb
(又名。 MySQL-python
),因此,我們最后只是communicate
荷蘭國際集團的數據subprocess.Popen([mysql, ...], stdin=subprocess.PIPE)
和檢查returncode
.
嘗試了multi=True
方法,但最終通過半分割和循環來分割文件。 如果你已經逃脫了半決賽,顯然不會起作用,但對我來說似乎是最好的方法。
with connection.cursor() as cursor:
for statement in script.split(';'):
if len(statement) > 0:
cursor.execute(statement + ';')
通過 Popen 使用mysql
程序肯定會起作用,但是如果您只想使用現有的連接(和游標), sqlparse
包有一個split
函數,它將拆分為語句。 我不確定兼容性是什么樣的,但我有一個腳本可以:
with open('file.sql', 'rb') as f:
for statement in sqlparse.split(f.read()):
if not statement:
continue
cur.execute(statement)
它只提供 DROP TABLE 和 CREATE TABLE 語句,但對我有用。
for _ in cursor.execute(query, multi=True):
pass
這對我有用!
根據文檔,這是正確的做法, cursor.execute() 返回一個迭代器,只有當迭代器中的內容被消耗時,提交才會成功。
使用下面的行項目來執行語句:
for _ in cursor.execute(query, multi=True): pass
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.