Python查询tbl_timeout触发InternalError问题求助
希望先验证emp_id的有效性,再查询并展示tbl_timeout表中对应员工的记录,但运行Python代码时终端持续抛出如下错误:
raise InternalError("Unread result found")
mysql.connector.errors.InternalError: Unread result found
File "c:\Users\Booster\Documents\python\main.py", line 230, in showtimeout
if con.is_connected():
File "C:\Users\Booster\AppData\Local\Programs\Python\Python310\lib\site-packages\mysql\connector\connection_cext.py", line 322, in is_connected
self.handle_unread_result()
相关代码块:
def showtimeout(): timerec = tkinter.Tk() timerec.title("Time in Records") timerec.geometry("600x200") try: con = mysql.connector.connect(host='localhost', port='3306', database='db_empdb', user='root', password='') tree=ttk.Treeview(timerec) cursor = con.cursor() query = "SELECT emp_id FROM tbl_employee WHERE emp_id = %s" cursor.execute(query, (adwin_entry.get(),)) result = cursor.fetchone() if result: query = f"SELECT * FROM tbl_timeout WHERE emp_id = {adwin_entry.get()}" cursor.execute(query) con.commit() rows=cursor.fetchall() columns = [desc[0] for desc in cursor.description] tree["columns"] = columns tree.heading("#0", text="Index") for col in columns: tree.heading(col, text=col) tree.column(col, width=100, anchor="center") for i, row in enumerate(rows): tree.insert("", "end", text=str(i), values=row) tree.pack(fill="both", expand=True) con.commit() cursor.close() else: messagebox.showerror("Failed", "Employee ID not found!") except Error as err: print("Access Failed! {}".format(err)) finally: if con.is_connected(): con.close() print("Connection Successful!")
这个错误核心原因是MySQL Connector/Python的游标在执行新查询前,未完全读取上一次查询的结果集,同时代码还存在其他风险和冗余操作,以下是具体修复方案:
1. 解决未读结果集问题
第一次执行SELECT emp_id后,即便调用了fetchone(),若表中存在重复emp_id,游标仍会残留未读取的结果。复用同一个游标执行新查询时,就会触发"Unread result found"错误。
修复方式:
- 为不同查询创建独立游标(更推荐,避免结果集冲突);
- 或在执行新查询前,调用
cursor.fetchall()清空所有未读结果。
2. 移除不必要的事务提交
SELECT查询不需要调用con.commit(),该操作仅针对INSERT/UPDATE/DELETE等写操作,多余的提交会造成无效事务开销。
3. 修复SQL注入漏洞
代码中用f-string拼接SQL语句f"SELECT * FROM tbl_timeout WHERE emp_id = {adwin_entry.get()}"存在严重SQL注入风险,必须改用参数化查询,和第一次验证查询的写法保持一致。
修复后的完整代码
def showtimeout(): timerec = tkinter.Tk() timerec.title("Time in Records") timerec.geometry("600x200") try: con = mysql.connector.connect(host='localhost', port='3306', database='db_empdb', user='root', password='') tree=ttk.Treeview(timerec) # 验证emp_id有效性,使用独立游标 validate_cursor = con.cursor() query = "SELECT emp_id FROM tbl_employee WHERE emp_id = %s" validate_cursor.execute(query, (adwin_entry.get(),)) result = validate_cursor.fetchone() validate_cursor.close() if result: # 查询超时记录,使用新游标 query_cursor = con.cursor() # 参数化查询,避免SQL注入 query = "SELECT * FROM tbl_timeout WHERE emp_id = %s" query_cursor.execute(query, (adwin_entry.get(),)) rows = query_cursor.fetchall() columns = [desc[0] for desc in query_cursor.description] tree["columns"] = columns tree.heading("#0", text="Index") for col in columns: tree.heading(col, text=col) tree.column(col, width=100, anchor="center") for i, row in enumerate(rows): tree.insert("", "end", text=str(i), values=row) tree.pack(fill="both", expand=True) query_cursor.close() else: messagebox.showerror("Failed", "Employee ID not found!") except Error as err: print("Access Failed! {}".format(err)) finally: # 先判断连接对象是否存在,避免未建立连接时触发错误 if 'con' in locals() and con.is_connected(): con.close() print("Connection closed!")
额外优化点
- 在
finally块中增加con的存在性判断,避免未建立连接时抛出NameError; - 拆分游标职责,验证和查询使用独立游标,代码逻辑更清晰;
- 移除所有
SELECT操作后的无效commit()调用。
内容的提问来源于stack exchange,提问作者Marsh

