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

.NET Framework 4.0并发调用存储过程生成CSV文件缺失问题排查

问题排查:并发调用存储过程生成CSV仅部分成功

核心问题分析

1. 数据库连接管理不当

代码中创建SqlConnection实例后,依赖DB.Connect_SQLDataTable处理连接,但如果该方法未正确打开、关闭或释放连接,并发场景下会导致连接池耗尽,部分任务无法获取连接执行存储过程,最终返回空数据。

2. UI控件线程不安全访问

divHtml.InnerHtml是ASP.NET WebForms服务器控件,多线程(Task)直接修改会触发跨线程访问异常(部分场景下异常被静默吞掉,但会中断后续逻辑),导致任务提前终止,无法生成文件。

3. SQL拼接的日期格式风险

直接将strDate拼接进SQL语句,即便用了yyyy-MM-dd格式,若存储过程对日期参数格式验证严格,或数据库语言/日期设置不匹配,会导致参数解析错误,存储过程返回空结果,同时存在SQL注入风险。

4. 异常处理不完整

文件创建的try/catch仅返回空字符串,未记录错误信息;DB.Connect_SQLDataTable返回false时,也未处理strErr,无法定位数据库层面的失败原因。


修复方案

1. 正确管理数据库连接

用using语句包裹连接,确保自动释放,同时改用参数化查询避免格式问题:

string SQL = "EXEC [BMC_LoadPatientServices_New] @Date, '', '', '%He%', '%OPD%'";
string strErr = string.Empty;

using (SqlConnection con = new SqlConnection(DB.GetConnectionString()))
{
    using (SqlCommand cmd = new SqlCommand(SQL, con))
    {
        cmd.Parameters.Add("@Date", SqlDbType.Date).Value = DateTime.Parse(strDate);
        try
        {
            con.Open();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dtView = new DataTable();
            da.Fill(dtView);
            
            // 后续dtView处理逻辑...
        }
        catch (Exception ex)
        {
            strErr = ex.Message;
            // 写入错误日志,比如本地文本文件
        }
    }
}

2. 避免跨线程修改UI控件

改用线程安全容器收集状态,任务完成后统一更新UI:

// 定义线程安全容器
ConcurrentBag<string> taskStatuses = new ConcurrentBag<string>();

// 在PopulateDateData中替换divHtml修改逻辑:
// divHtml.InnerHtml += ", Date: " + strDate;
taskStatuses.Add(", Date: " + strDate);

// 所有任务完成后统一更新UI
Task.WaitAll(taskArray);
divHtml.InnerHtml += string.Join("", taskStatuses);

3. 完善异常处理与日志

在关键步骤添加日志记录,方便定位失败原因:

// 文件创建异常处理优化
try
{
    using (FileStream fs = File.Create(file))
    {
        Byte[] title = new UTF8Encoding(true).GetBytes(builder.ToString());
        fs.Write(title, 0, title.Length);
    }
}
catch (Exception ex)
{
    File.AppendAllText(Server.MapPath("~/Logs/csv_error.log"), 
        $"Date: {strDate}, Error: {ex.Message}{Environment.NewLine}");
    return $"Error: {ex.Message}";
}

// 数据库连接失败时记录日志
if (!DB.Connect_SQLDataTable(ref dtView, SQL, ref con, ref strErr))
{
    File.AppendAllText(Server.MapPath("~/Logs/db_error.log"), 
        $"Date: {strDate}, DB Error: {strErr}{Environment.NewLine}");
}

4. 优化Task创建逻辑

确保每个Task的日期参数被正确捕获,避免闭包陷阱:

Task<string>[] taskArray = new Task<string>[5];
DateTime currentDate = DateTime.Now.Date; // 仅保留日期部分,避免时间干扰

for (int i = 0; i < taskArray.Length; i++)
{
    string targetDate = currentDate.AddDays(-(i+1)).ToString("yyyy-MM-dd");
    taskArray[i] = Task.Factory.StartNew(() => PopulateDateData(targetDate));
}

Task.WaitAll(taskArray);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 16:25:02