Python mysql.connector cursor.execute() 和 connection.commit() 不在循环中工作

Python mysql.connector cursor.execute() and connection.commit() not working in a loop

尝试使用 for-loop

自动处理 MySQL 中的表
from mysql.connector import connect, Error

def main():
    try:
        with connect(host="host", user="user",password="password") as connection:
            connection.autocommit = True
            no_pk_tables_query = """
            select tab.table_schema as database_name,
                tab.table_name
            from information_schema.tables tab
            left join information_schema.table_constraints tco
                on tab.table_schema = tco.table_schema
                and tab.table_name = tco.table_name
                and tco.constraint_type = 'PRIMARY KEY'
            where tco.constraint_type is null
                and tab.table_schema not in('mysql', 'information_schema', 
                                  'performance_schema', 'sys')
                and tab.table_type = 'BASE TABLE'
                order by tab.table_schema,
            tab.table_name;
            """
            tables_to_cure = []
            with connection.cursor() as cursor:
                cursor.execute(no_pk_tables_query)
                for table in cursor:
                    tables_to_cure.append(table[1])
                    print(table[1])
                
                for s_table in tables_to_cure:
                        cure = """
                                USE mission_impossible;
                                ALTER TABLE `{}` MODIFY `ID` int(18) NOT NULL auto_increment PRIMARY KEY;
                            """.format(s_table)
                        cursor.execute(cure)
                        print("Cured {}".format(s_table))             
    except Error as e:
        print(e)
    finally:
        print("End")

main()

然后我得到:

quote 2014 (HY000): 命令不同步;你现在不能运行这个命令

如果我在 cursor.execute() 之后的 for 循环内添加 connection.commit() 我会得到:

_mysql_connector.MySQLInterfaceError:命令不同步;你现在不能运行这个命令

这是否意味着我必须在循环内使用新连接而不是游标? 我查了一下,发现了一些像 fetchall()nextset() 这样的方法,但它们似乎除了简单地刷新当前游标数据之外还做了其他事情。 使用 connection.autocommit = True 似乎也不起作用,因为发生了同样的错误。 使用 sleep() 之类的东西也无济于事。 我在这里做错了什么?

编辑

摆脱 try/except 没有帮助:

  File "/usr/local/lib/python3.8/dist-packages/mysql/connector/connection_cext.py", line 523, in cmd_query
    self._cmysql.query(query,
_mysql_connector.MySQLInterfaceError: Commands out of sync; you can't run this command now

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "db.py", line 40, in <module>
    main()
  File "db.py", line 36, in main
    cursor.execute(cure)
  File "/usr/local/lib/python3.8/dist-packages/mysql/connector/cursor_cext.py", line 269, in execute
    result = self._cnx.cmd_query(stmt, raw=self._raw,
  File "/usr/local/lib/python3.8/dist-packages/mysql/connector/connection_cext.py", line 528, in cmd_query
    raise errors.get_mysql_exception(exc.errno, msg=exc.msg,
mysql.connector.errors.DatabaseError: 2014 (HY000): Commands out of sync; you can't run this command now

固定:

看来我终于弄明白了,需要使用 fetchall() 从游标中获取结果,而不是直接将游标作为迭代器进行寻址。

            with connection.cursor() as cursor:
                cursor.execute(no_pk_tables_query)
                rows = cursor.fetchall()
            with connection.cursor() as cursor:
                for table in rows:
                    try:
                        print(table[1])
                        cure = """
                            ALTER TABLE `{}` MODIFY `ID` int(18) NOT NULL auto_increment PRIMARY KEY;
                        """.format(table[1])
                        cursor.execute(cure)
                        res = cursor.fetchall()
                        print(res)
                    except Error as e:
                        print(e)

谢谢大家

下面是一些示例代码,显示了“命令不同步”错误是如何发生的:

from mysql.connector import connect, Error
# replace asterisks in the CONFIG dictionary with your data
CONFIG = {
    'user': '*',
    'password': '*',
    'host': '*',
    'database': '*',
    'autocommit': False
}
try:
    with connect(**CONFIG) as conn:
        try:
            with conn.cursor() as cursor:
                cursor.execute('select * from ips')
                # cursor.fetchall()
        finally:
            conn.commit()
except Error as e:
    print(e)

解释:

代码 select 是来自名为“ips”的 table 的所有行,其内容与此处无关。

现在,请注意我们不会尝试获取行集(fetchall 已被注释掉)。然后我们尝试提交事务(即使未对 table 进行任何更改)。

这会导致“命令不同步”错误。

但是,如果我们取出注释行并获取行集(fetchall),则不会出现此问题。

显式获取行集等同于遍历游标。

如果我们将自动提交参数更改为 True 并删除显式 commit(),我们会收到另一个错误:-“找到未读结果”。

换句话说,似乎 MySQL 要求 您在 select 任何时候获取行集(或遍历游标)!

请注意,即使启用了自动提交 (True),也允许显式调用 commit()

解决方案:

要么确保客户端应用程序在 SELECT 之后遍历整个游标,要么在 CONFIG 字典中添加:'consume_results': True