You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Tornado WebSocket的PyMySQL返回重复结果而非最新数据求助

解决Tornado WebSocket返回重复旧数据的问题

我仔细看了你的代码和问题描述,发现几个关键问题导致你每次都拿到旧数据,甚至还有语法错误和方法调用错误,一步步来解决:

一、最直接的错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:15:28