PythonMySQL 连接器-使用 fetchone 时发现未读结果

我将 JSON 数据插入到 MySQL 数据库中

我正在解析 JSON,然后使用 python 连接器将其插入到 MySQL 数据库中

通过试用,我发现这个错误与这段代码有关

for steps in result['routes'][0]['legs'][0]['steps']:
query = ('SELECT leg_no FROM leg_data WHERE travel_mode = %s AND Orig_lat = %s AND Orig_lng = %s AND Dest_lat = %s AND Dest_lng = %s AND time_stamp = %s')
if steps['travel_mode'] == "pub_tran":
travel_mode = steps['travel_mode']
Orig_lat = steps['var_1']['dep']['lat']
Orig_lng = steps['var_1']['dep']['lng']
Dest_lat = steps['var_1']['arr']['lat']
Dest_lng = steps['var_1']['arr']['lng']
time_stamp = leg['_sent_time_stamp']
if steps['travel_mode'] =="a_pied":
query = ('SELECT leg_no FROM leg_data WHERE travel_mode = %s AND Orig_lat = %s AND Orig_lng = %s AND Dest_lat = %s AND Dest_lng = %s AND time_stamp = %s')
travel_mode = steps['travel_mode']
Orig_lat = steps['var_2']['lat']
Orig_lng = steps['var_2']['lng']
Dest_lat = steps['var_2']['lat']
Dest_lng = steps['var_2']['lng']
time_stamp = leg['_sent_time_stamp']
cursor.execute(query,(travel_mode, Orig_lat, Orig_lng, Dest_lat, Dest_lng, time_stamp))
leg_no = cursor.fetchone()[0]
print(leg_no)

我已经插入了更高级别的详细信息,现在正在搜索数据库,将这个较低级别的信息与它的父级关联起来。找到这个唯一值的唯一方法是通过原点和目的地与 time _ 戳的坐标进行搜索。我相信这个逻辑是合理的,并且通过在这个部分之后立即打印 leg _ no,我可以看到在第一次检查时出现的数值是正确的

但是,当添加到代码的其余部分时,它会导致后续的部分,其中使用游标插入更多的数据,从而导致这个错误-

    raise errors.InternalError("Unread result found.")
mysql.connector.errors.InternalError: Unread result found.

这个问题似乎与 使用 Python 的 MySQL 未读结果类似

是查询过于复杂,需要分割,还是存在其他问题?

如果查询确实过于复杂,有人能提出如何最好地分割它吗?

根据@Gord 的帮助,我试图转储任何未读的结果

cursor.execute(query,(leg_travel_mode, leg_Orig_lat, leg_Orig_lng, leg_Dest_lat, leg_Dest_lng))
leg_no = cursor.fetchone()[0]
try:
cursor.fetchall()
except mysql.connector.errors.InterfaceError as ie:
if ie.msg == 'No result set to fetch from.':
pass
else:
raise
cursor.execute(query,(leg_travel_mode, leg_Orig_lat, leg_Orig_lng, leg_Dest_lat, leg_Dest_lng, time_stamp))

但是,我仍然得到

raise errors.InternalError("Unread result found.")
mysql.connector.errors.InternalError: Unread result found.
[Finished in 3.3s with exit code 1]

挠头

编辑2-当我打印 ie.msg 时,我得到-

No result set to fetch from
167568 次浏览

我重现了你的问题。MySQL Connector/Python 显然不喜欢在关闭游标或使用它检索其他内容之前检索多行并且不能全部获取它们。比如说

import mysql.connector
cnxn = mysql.connector.connect(
host='127.0.0.1',
user='root',
password='whatever',
database='mydb')
crsr = cnxn.cursor()
crsr.execute("DROP TABLE IF EXISTS pytest")
crsr.execute("""
CREATE TABLE pytest (
id INT(11) NOT NULL AUTO_INCREMENT,
firstname VARCHAR(20),
PRIMARY KEY (id)
)
""")
crsr.execute("INSERT INTO pytest (firstname) VALUES ('Gord')")
crsr.execute("INSERT INTO pytest (firstname) VALUES ('Anne')")
cnxn.commit()
crsr.execute("SELECT firstname FROM pytest")
fname = crsr.fetchone()[0]
print(fname)
crsr.execute("SELECT firstname FROM pytest")  # InternalError: Unread result found.

如果您只期望(或关心)一行,那么您可以在查询中放置 LIMIT

crsr.execute("SELECT firstname FROM pytest LIMIT 0, 1")
fname = crsr.fetchone()[0]
print(fname)
crsr.execute("SELECT firstname FROM pytest")  # OK now

或者可以使用 fetchall()在处理完检索到的行之后去除任何未读的结果。

crsr.execute("SELECT firstname FROM pytest")
fname = crsr.fetchone()[0]
print(fname)
try:
crsr.fetchall()  # fetch (and discard) remaining rows
except mysql.connector.errors.InterfaceError as ie:
if ie.msg == 'No result set to fetch from.':
# no problem, we were just at the end of the result set
pass
else:
raise
crsr.execute("SELECT firstname FROM pytest")  # OK now

所需要的只是 buffered设置为 true!

cursor = cnx.cursor(buffered=True)

原因是没有缓冲的游标,结果是“延迟”加载的,这意味着“ fetchone”实际上只从查询的完整结果集中获取一行。当您再次使用相同的游标时,它会抱怨您仍然有 n-1个结果(其中 n 是结果集数量)等待获取。但是,当您使用一个缓冲光标时,连接器将在后台获取所有行,您只需从连接器中获取一行,这样 mysql db 就不会抱怨。

您与 MySQLWorkbench 的连接也有可能断开。再次建立联系。这为我解决了问题。

在 for 循环中设置光标,执行它,然后在循环中再次关闭它会有帮助吗? 比如:

for steps in result['routes'][0]['legs'][0]['steps']:
cursor = cnx.cursor()
....
leg_no = cursor.fetchone()[0]
cursor.close()
print(leg_no)

cursor.reset()才是你真正想要的。

fetchall()不好,因为您可能最终会将不必要的数据从数据库移动到客户端。

如果您只想从请求中获得一个结果,并且希望在此之后为其他请求重用相同的连接,那么在请求的末尾使用“ limit 1”将 sql select 请求限制为1。

ex "Select field from table where x=1 limit 1;"

使用“ buffer = True”这个方法更快

问题在于缓冲区,可能您从上一个 MySQL 连接断开了连接,现在它无法执行下一个语句。有两种方法可以将缓冲区提供给游标。首先,使用以下命令只对特定的游标进行操作:

import mysql.connector


cnx = mysql.connector.connect()


# Only this particular cursor will buffer results
cursor = cnx.cursor(buffered=True)

或者,您可以为您使用的任何游标启用 buffer:

import mysql.connector


# All cursors created from cnx2 will be buffered by default
cnx2 = mysql.connector.connect(buffered=True)


cursor = cnx.cursor()

如果您断开了与 MySQL 的连接,后者将为您工作。 享受编程吧

connect()方法上的 consume_results参数设置为 True

cnx = mysql.connector.connect(
host="localhost",
user="user",
password="password",
database="database",
consume_results=True
)

现在,它基本上不引发异常,而是执行 fetchall()
不幸的是,如果有很多未读行,这仍然会使它变慢。

游标,复位() 然后创建表和加载条目