簡體   English   中英

MySQLdb.cursor.execute 不能運行多個查詢

[英]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=Trueexecute ,請參閱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 語句,但對我有用。

https://pypi.python.org/pypi/sqlparse

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM