fix: 修复并发安全问题导致的数据库崩溃和数据错乱
问题根因:
FileSortTimer 每15秒触发 Task.Run 执行 ProcessFiles(),当P盘文件量大时
上一轮未完成新一轮又启动,多线程并发操作同一数据库连接和全局变量,导致:
1. SQLHelper 静态 SqlConnection/SqlCommand/SqlDataReader 被多线程覆盖,连接状态异常
2. ConfigDfn.strEquipNo 等全局静态变量被并发覆盖,事件触发时使用错误车号
3. 定时器无重入保护,多个 ProcessFiles() 实例并发执行
4. HasBothSidesMeasureResult 查询返回空表时直接访问列导致崩溃
修复内容:
[P0] SQLHelper.cs - 线程安全改造
- 删除静态 conn/cmd/sdr 字段和 GetConn() 方法
- 所有方法(ExecuteQuery/ExecuteNonQuery/ExecuteDs/BulkCopy)改为 using 独立连接模式
- 每次调用创建独立 SqlConnection,彻底消除连接竞争
[P0] FormMain.cs - 防止定时器重入
- 新增 _isProcessing 原子标志位(Interlocked.CompareExchange)
- FileSortTimer_Tick 检测到上一轮仍在执行时跳过本次触发
- finally 块确保标志位一定被释放
[P1] FileSorter.cs - 消除全局变量竞争
- 新增 CsvParseResult 类封装解析结果(CarID/CarModel/Position/MeasureTime)
- ImportCsv2Sql 改为返回 CsvParseResult,不再写入 ConfigDfn 全局变量
- GenerateSingleSideStatistics 改为参数传入(carID/carModel/groupName/position/measureTime)
- GenCustomerReport/GenerateCsvReport 改为参数传入 carModel
- OnFileParsed 事件改为三参数签名(carID, position, measureTime)
[P1] FormMain.cs - UI事件适配
- FileSorter_OnFileParsed 适配新的三参数签名
- DisplayMeasureData 接收 measureTime 参数,不再从全局变量读取
[P2] CjlrDAL.cs - 防御性检查
- HasBothSidesMeasureResult 增加 carId 空值检查
- 增加 dt.Columns.Contains("HasBothSides") 检查,避免空表异常
[P2] FileSorter.cs - 增强日志
- ProcessFiles() 开头打印查询到的任务总数,便于现场确认任务是否全部加载
影响文件:
- Analysis/DAL/SQLHelper.cs
- Analysis/CjlrForm/FileSorter.cs
- Analysis/FormMain.cs
- Analysis/DAL/CjlrDAL.cs
This commit is contained in:
@@ -234,6 +234,9 @@ NULLIF(
|
||||
// check 是否有左右两侧的测量结果
|
||||
public bool HasBothSidesMeasureResult(string carId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(carId))
|
||||
return false;
|
||||
|
||||
string sql = @"
|
||||
SELECT CASE
|
||||
WHEN COUNT(DISTINCT Remark) = 2 THEN 1
|
||||
@@ -246,7 +249,10 @@ NULLIF(
|
||||
new SqlParameter("@CarID", carId)
|
||||
};
|
||||
DataTable dt = SQLHelper.ExecuteQuery(sql, paras, CommandType.Text);
|
||||
return dt.Rows.Count > 0 && Convert.ToInt32(dt.Rows[0]["HasBothSides"]) == 1;
|
||||
// 防御性检查:空表或列不存在时返回 false,避免 Column 'HasBothSides' does not belong to table 异常
|
||||
if (dt == null || dt.Rows.Count == 0 || !dt.Columns.Contains("HasBothSides"))
|
||||
return false;
|
||||
return Convert.ToInt32(dt.Rows[0]["HasBothSides"]) == 1;
|
||||
}
|
||||
|
||||
// 查询指定车辆ID的测量点维度数据
|
||||
|
||||
Reference in New Issue
Block a user