基于Tornado WebSocket的PyMySQL返回重复结果而非最新数据求助
我仔细看了你的代码和问题描述,发现几个关键问题导致你每次都拿到旧数据,甚至还有语法错误和方法调用错误,一步步来解决:
一、最直接的错误:on_message方法没有调用查询方法
你的on_message里写的是json.dumps(self.EnergyDB),但self.EnergyDB是方法对象,不是执行结果!而且Tornado的on_message必须接收message参数,否则框架无法正确触发这个方法。修复后:
def on_message(self, message): # 调用EnergyDB()获取最新数据,而不是直接用方法对象 latest_data = self.EnergyDB() # 用convert处理datetime类型,避免序列化失败 self.write_message(json.dumps(latest_data, default=self.convert))
二、SQL拼接逻辑错误:ORDER BY被当成WHERE条件
你的fetch_row方法参数设计有问题,当flag=None时,会把value当成WHERE子句的取值,导致生成的SQL完全不符合预期(甚至语法错误)。重新设计这个方法,让它支持正确的SQL子句拼接:
class DbConnection(): def __init__(self, host='localhost', port=3306, user='user', password='password', db_name=None, cursor_type=None): self.connection = pymysql.connect( host=host, user=user, passwd=password, port=port, database=db_name, charset='utf8', autocommit=True # 关键:开启自动提交,确保每次查询都能看到最新数据 ) # 游标创建逻辑不变 if cursor_type is None: self.cursor = self.connection.cursor(pymysql.cursors.SSCursor) else: self.cursor = self.connection.cursor(pymysql.cursors.SSDictCursor) def fetch_row(self, data='*', table=None, where_clause=None, order_by=None, limit=None): if not table: raise ValueError("必须指定表名") sql_parts = [f"SELECT {data} FROM {table}"] if where_clause: sql_parts.append(f"WHERE {where_clause}") if order_by: sql_parts.append(f"ORDER BY {order_by}") if limit: sql_parts.append(f"LIMIT {limit}") sql = " ".join(sql_parts) self.cursor.execute(sql) return self.cursor.fetchall()
三、事务快照问题:未开启自动提交导致读取旧数据
MySQL默认事务隔离级别是REPEATABLE READ,如果不开启autocommit=True,同一个连接下的所有查询都会在同一个事务中,读取的是事务启动时的数据快照,看不到后续的更新。上面的DbConnection初始化已经加上了autocommit=True,解决这个问题。
四、修正EnergyDB方法的调用
现在用新的fetch_row方法获取最新数据:
def EnergyDB(self): # 获取按时间倒序的第一条最新数据 return self.db_connection.fetch_row( table="Energy", order_by="Timestamp DESC", limit=1 )
关于游标复用和CPU过载的问题
复用同一个连接和游标是完全正确的做法,不需要每次请求都新建游标/连接——频繁创建数据库连接才是CPU过载的元凶,因为建立连接的开销很大。只要开启了autocommit=True,每次执行cursor.execute()都会重新查询最新数据,不会复用旧的结果集。
另外,SSDictCursor是服务器端游标,适合处理大量数据,对于单条数据的查询,用普通的DictCursor也可以,性能差别不大,但服务器端游标不会把所有结果加载到内存,大数据量场景更友好。
修复完成后,客户端每10秒发送请求时,服务器都会查询数据库的最新数据并返回,就能拿到传感器的实时数据了。
内容的提问来源于stack exchange,提问作者SparkyWolf

