基于Raspberry Pi的多用户考勤系统故障求助:多用户打卡逻辑异常
解决多用户考勤系统的状态混乱问题
核心问题分析
你用全局变量sign_in控制所有用户的打卡状态,这必然导致多用户场景下逻辑混乱——系统只会记住上一次操作的全局状态,而非每个用户独立的状态。必须改成从数据库读取当前用户的最新状态来判断打卡/退卡操作。
具体修改方案
- 移除全局状态变量:删掉
sign_in和sign_out全局变量,每次读卡后单独查询当前用户的最新考勤记录。 - 查询用户最新状态:通过SQL获取该用户最后一条考勤记录的
signed_in状态和clock_out值,以此判断操作类型。 - 分逻辑处理打卡/退卡:
- 若用户无考勤记录,或最后一条记录
signed_in=0且clock_out不为空(上次已正常退卡),则新增打卡记录,写入clock_in并设signed_in=1。 - 若最后一条记录
signed_in=1(用户处于打卡状态),则更新该记录的clock_out字段,同时设signed_in=0。
- 若用户无考勤记录,或最后一条记录
- 修复数据库操作问题:用参数化查询避免SQL注入,所有数据库操作后执行
db.commit()确保数据即时写入。
修改后的完整代码
#!/usr/bin/env python import time import datetime import RPi.GPIO as GPIO from mfrc522 import SimpleMFRC522 import mysql.connector import drivers # 数据库连接 db = mysql.connector.connect( host="localhost", user="xxx", passwd="xxx", database="attendancesystem" ) cursor = db.cursor() reader = SimpleMFRC522() display = drivers.Lcd() try: while True: display.lcd_clear() display.lcd_display_string("Transponder", 1) display.lcd_display_string("platzieren", 2) # 读取RFID卡 id, text = reader.read() current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 查询用户信息 cursor.execute("SELECT id, name FROM users WHERE rfid_uid = %s", (id,)) user = cursor.fetchone() display.lcd_clear() if not user: display.lcd_display_string("Existiert nicht.", 1) time.sleep(2) continue user_id, user_name = user # 查询该用户最新的考勤记录 cursor.execute(""" SELECT signed_in, clock_out FROM attendance WHERE user_id = %s ORDER BY id DESC LIMIT 1 """, (user_id,)) latest_record = cursor.fetchone() # 处理打卡/退卡逻辑 if not latest_record or (latest_record[0] == 0 and latest_record[1] is not None): # 无记录或已退卡,执行打卡 cursor.execute(""" INSERT INTO attendance (user_id, clock_in, signed_in) VALUES (%s, %s, 1) """, (user_id, current_time)) display.lcd_display_string(f"Angemeldet {user_name}", 1) elif latest_record[0] == 1: # 已打卡,执行退卡 cursor.execute(""" UPDATE attendance SET clock_out = %s, signed_in = 0 WHERE user_id = %s ORDER BY id DESC LIMIT 1 """, (current_time, user_id)) display.lcd_display_string(f"Abgemeldet {user_name}", 1) else: # 异常状态(比如存在未完成的打卡记录) display.lcd_display_string("Fehler: Status", 1) display.lcd_display_string("ungültig", 2) # 提交数据库修改 db.commit() time.sleep(2) finally: GPIO.cleanup() cursor.close() db.close()
额外注意事项
- 数据库索引优化:给
attendance表的user_id字段加索引,加快最新记录的查询速度。 - 异常处理:可给数据库操作添加
try-except捕获异常,避免系统因数据库错误崩溃。 - 资源释放:代码末尾关闭数据库游标和连接,避免资源泄漏。
内容的提问来源于stack exchange,提问作者M. Pablo
相关产品推荐
相关产品推荐

