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

C#中MySqlDataReader与Timer同步异常问题排查求助

轮询MySQL视图输出不同步问题排查与修复

问题概述

使用Timer组件轮询MySQL数据库视图,几轮后输出出现不同步现象,且该问题与轮询时长无关。以下是相关代码及输出日志,结合内容排查问题原因。

代码核心问题分析

从提供的代码来看,输出不同步的根源在于以下几点:

  1. Timer重复实例化与事件重复绑定
    每次调用startPoll都会创建新的Timer实例,并且重复绑定Elapsed事件。这会导致多个Timer同时运行,多个查询任务并行执行,输出结果交叉混乱,对应日志里重复的Timer Started和交错的查询输出。
  2. UI线程操作不安全
    在Timer的Elapsed事件逻辑中直接修改stateText的文本和颜色,而Elapsed事件运行在非UI线程,直接操作UI控件会引发线程安全问题,可能导致隐性的同步异常。
  3. 数据库资源冗余释放
    代码已用using语句包裹MySqlConnection、MySqlCommand和MySqlDataReader,这些对象会在using块结束时自动释放资源,手动调用rdr.Close()和conn.Close()属于冗余操作,甚至可能引发资源释放顺序错误。
  4. 无增量查询逻辑
    每次查询都是SELECT * from vtokenpool limit 10,没有标记已处理的记录,导致重复输出相同数据,加上多线程并行执行,进一步加剧了输出混乱。

修复后的代码示例

// 全局仅初始化一次Timer
private Timer _pollingTimer;

private void StartPolling()
{
    // 避免重复创建Timer实例
    if (_pollingTimer == null)
    {
        int interval = int.Parse(Properties.Settings.Default.DbPoll) * 1000;
        _pollingTimer = new Timer(interval);
        _pollingTimer.Elapsed += HandlePollingEvent;
    }
    
    _pollingTimer.Stop();
    _pollingTimer.Start();
    System.Diagnostics.Debug.WriteLine("Timer Started " + Properties.Settings.Default.DbPoll + " secs");
}

private void HandlePollingEvent(object sender, ElapsedEventArgs e)
{
    // 查询前暂停Timer,避免并行执行
    _pollingTimer.Stop();
    
    string connectionString = $"server={Properties.Settings.Default.DbServer};database=digital_passports;uid={Properties.Settings.Default.DbUser};pwd={Properties.Settings.Default.DbPass}";
    
    try
    {
        using (var conn = new MySqlConnection(connectionString))
        {
            conn.Open();
            System.Diagnostics.Debug.WriteLine("Database Connection Connected");

            // 记录上次处理的最大ID,实现增量查询(假设视图有自增ID列)
            static long _lastProcessedId = 0;
            var stm = $"SELECT * from vtokenpool WHERE id > {_lastProcessedId} ORDER BY id LIMIT 10";

            using (var cmd = new MySqlCommand(stm, conn))
            {
                // 切换到UI线程更新控件状态
                stateText.Invoke(new Action(() =>
                {
                    stateText.Text = "Running";
                    stateText.ForeColor = System.Drawing.Color.Green;
                }));

                using (MySqlDataReader rdr = cmd.ExecuteReader())
                {
                    while (rdr.Read())
                    {
                        long currentId = Convert.ToInt64(rdr[0]);
                        System.Diagnostics.Debug.WriteLine(currentId + " -- " + rdr[1]);
                        
                        // 更新最后处理的ID,避免重复输出
                        if (currentId > _lastProcessedId)
                        {
                            _lastProcessedId = currentId;
                        }
                    }
                    System.Diagnostics.Debug.WriteLine("Reader Processing Completed");
                }
            }
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Polling Error: " + ex);
        // 切换到UI线程更新错误状态
        stateText.Invoke(new Action(() =>
        {
            stateText.Text = "Error";
            stateText.ForeColor = System.Drawing.Color.Red;
        }));
    }
    finally
    {
        // 重启Timer,保证下一轮轮询正常执行
        _pollingTimer.Start();
        System.Diagnostics.Debug.WriteLine("Timer Restarted");
    }
}

日志异常说明

从提供的输出日志可见:

  • 重复出现Timer Started、Timer Ended,说明存在多个Timer实例同时运行。
  • 查询结果交错输出(如59号记录多次出现),是因为多个并行的查询任务同时输出结果,导致顺序混乱。

修复后通过单Timer实例、查询前暂停Timer、增量查询逻辑,即可解决输出不同步的问题。

内容的提问来源于stack exchange,提问作者Sudomasochist

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 17:17:41