多异步任务引发SQL Server插入存储过程重复数据问题求助
核心问题:HashSet去重失效
你的HashSet<UserInfo>没有起到去重作用,原因是UserInfo作为结构体,默认的GetHashCode和Equals实现无法可靠识别字段完全相同的实例。默认结构体的哈希码生成逻辑并不保证基于所有字段的组合,导致两个值完全一致的UserInfo被判定为不同对象,从而被重复添加到HashSet中。
次要问题:任务创建逻辑错误
你的任务循环代码存在bug:每次循环都会覆盖task变量,最终Task.WaitAll(task)只会等待最后一个任务执行完成,之前的任务会在后台异步运行,这可能导致重复处理(不过你提到单任务也会出现重复,所以这不是核心原因,但必须修复)。
解决方案
1. 重写UserInfo的GetHashCode和Equals方法
为UserInfo结构体手动实现基于所有字段的哈希计算和相等判断,确保HashSet能正确识别重复项:
public struct UserInfo : IEquatable<UserInfo> { public string UserName { get; set; } public string Address { get; set; } public string AccountType { get; set; } public string AccountNumber { get; set; } public bool Equals(UserInfo other) { return UserName == other.UserName && Address == other.Address && AccountType == other.AccountType && AccountNumber == other.AccountNumber; } public override bool Equals(object obj) { return obj is UserInfo other && Equals(other); } public override int GetHashCode() { // 基于所有字段组合生成哈希码 return HashCode.Combine(UserName, Address, AccountType, AccountNumber); } }
2. 修复任务创建逻辑
改用列表存储所有任务,确保等待所有任务完成,同时避免闭包陷阱:
var tasks = new List<Task>(); foreach(var job in jobList) { var currentJob = job; tasks.Add(Task.Run(() => ProcessJobs(currentJob))); } Task.WaitAll(tasks.ToArray());
3. 修正消息获取逻辑
ProcessJobs方法中的getMessageFromQueue(message)存在变量未定义问题,推测应为getMessageFromQueue(job),请确认此处逻辑,避免同一个job重复获取相同的消息数据。
4. 数据库层面添加唯一约束(可选但推荐)
作为最后一道防线,在数据库表MyTable上添加基于业务字段的唯一约束,从根源上阻止重复数据插入:
ALTER TABLE MyTable ADD CONSTRAINT UQ_MyTable_UniqueUserInfo UNIQUE (UserName, Address, AccountType, AccountNumber);
如果需要允许AccountNumber为null的情况,可调整约束逻辑:
ALTER TABLE MyTable ADD CONSTRAINT UQ_MyTable_UniqueUserInfo UNIQUE (UserName, Address, AccountType, COALESCE(AccountNumber, ''));
额外说明
存储过程中@currentDate = CURRENT_TIMESTAMP的写法是正确的,它会为整个批次插入的行设置相同的创建时间,这也是重复行CreatedDate完全一致的原因,不属于问题点。
内容的提问来源于stack exchange,提问作者Terrance Jackson

