树莓派Python智能锁复用MySQL游标报Unread result found怎么办
问题原因与修复方案
报错触发逻辑
Unread result found是mysql-connector-Python的内置校验规则:同一个数据库游标在上一次执行SELECT查询后,如果没有把结果集全部消费读取完,就直接执行下一次SQL语句,连接器就会抛出该错误。
触发该错误的具体代码问题有两点:
- 匹配到用户的分支中,执行了
cursor.execute("Select secret From users Where rfid_uid="+str(id)),但完全没有对这次查询的结果做任何fetch读取操作,这次查询的返回结果会一直残留在游标的未读缓冲区里,等下一次循环用同一个游标执行新的SELECT语句时,就会触发报错。 - 这行二次查询本身完全冗余:第一次执行
Select id, name, secret From users Where rfid_uid=...时,已经把secret字段从数据库取出存在result[2]变量里,根本不需要再单独查询一次secret。
具体修复步骤
- 删除冗余的二次查询代码
直接删除cursor.execute("Select secret From users Where rfid_uid="+str(id))这一行,保留secret = result[2]的赋值逻辑即可,从根源上消除残留未读结果的触发源。 - 给游标加状态兜底,避免后续出现同类问题
两种方式二选一即可:- 方式一:初始化游标时开启缓冲模式,将原来创建游标的代码
cursor = conn.cursor()修改为cursor = conn.cursor(buffered=True)。该参数会让mysql-connector自动缓存查询的全部结果,执行下一次查询前自动清空上次的未读结果,不会再触发未读结果报错。 - 方式二:每一次查询取完需要的结果后,主动调用
cursor.fetchall()把剩余的未读结果全部读出,将游标重置为可执行下一次查询的状态。
- 方式一:初始化游标时开启缓冲模式,将原来创建游标的代码
- 修复代码中的潜在隐患
- 现有SQL通过字符串拼接传入RFID UID,存在SQL注入风险,需要改成参数化查询,将原来的拼接SQL:
cursor.execute("Select id, name, secret From users Where rfid_uid="+str(id))
修改为参数化写法:cursor.execute("Select id, name, secret From users Where rfid_uid=%s", (str(id),)) - 原有通过
cursor.rowcount >=1判断是否匹配到用户的逻辑,在调用fetchone()后判断结果并不可靠,直接判断result变量是否为None即可:如果返回结果为None,说明数据库中没有匹配的RFID UID;否则就走正常的用户匹配流程。
- 现有SQL通过字符串拼接传入RFID UID,存在SQL注入风险,需要改成参数化查询,将原来的拼接SQL:
修复后的核心循环参考代码
while True: print("Place card near the scanner") mylcd.lcd_display_string("Place card near",1) mylcd.lcd_display_string("the scanner",2) id, text = reader.read() # 参数化查询 cursor.execute("Select id, name, secret From users Where rfid_uid=%s", (str(id),)) result = cursor.fetchone() # 主动清空游标未读结果,避免状态卡住 cursor.fetchall() if result: _, user_name, secret = result mylcd.lcd_clear() print("Welcome, ", user_name) mylcd.lcd_display_string("Welcome",1) mylcd.lcd_display_string(user_name,2) time.sleep(2) mylcd.lcd_clear() print("Type the code from your authenticator") mylcd.lcd_display_string("Type in the code",1) totp = pyotp.TOTP(str(secret)) otp = totp.now() your_code = input('') mylcd.lcd_display_string(your_code,2) if your_code == otp: mylcd.lcd_clear() print("Code Valid, Opening the door") mylcd.lcd_display_string("Code Valid",1) mylcd.lcd_display_string("Opening the door",2) time.sleep(5) else: mylcd.lcd_display_string("Invalid Code",1) print("Invalid") time.sleep(5) mylcd.lcd_clear()
内容的提问来源于stack exchange,提问作者Al-
相关产品推荐
相关产品推荐

