[EF Core] 多线程执行SQL Command
public class XXXRepository { //数据库上下文 private XXXDBContext context; //作用域服务工厂 private readonly IServiceScopeFactory _serviceScopeFactory; public XXXRepository(XXXDBContext context, IServiceScopeFactory serviceScopeFactory) { this.context = context; _serviceScopeFactory = serviceScopeFactory; } }
public void XXXMethod() { // 开启数据库连接 context.Database.OpenConnection(); // 多线程任务列表 List<Task> tasks = new List<Task>(); // 线程安全先进先出集合 ConcurrentQueue<XXX> queue = new ConcurrentQueue<XXX>(); // SQL参数列表 -- 任务公有参数 List<SqlParameter> sqlParameters = new List<SqlParameter>(){ (new SqlParameter("@参数1", "参数值"), (new SqlParameter("@参数2", "参数值"), (new SqlParameter("@参数3", "参数值") }; // 循环创建任务 XXXStringList.ForEach(paramater => { // 任务私有参数 // 因为任务将在ForEach执行完后才开始运行,这意味着所有任务将会使用同一个参数值 // 所以需要使用一个变量来存储参数值,保证每个任务都使用独立的变量 string param = paramater; // 添加任务到任务列表 tasks.Add( // 创建并运行任务 Task.Run(async () => { try { // 创建作用域服务 using (var scope = _serviceScopeFactory.CreateScope()) { using (var _dbcontext = scope.ServiceProvider.GetService<XXXContext>()) { using (var command = context.Database.GetDbConnection().CreateCommand()) { command.Parameters.Clear(); // 添加任务私有参数 command.Parameters.Add(new SqlParameter("@PARAM", param)); // 添加任务公有参数 // 如果前面使用了SQL Command并且也使用了command.Parameters.Add()或command.Parameters.AddRange() // 再次添加参数时可能会出现报错 -- The SqlParameter is already contained by another SqlParameterCollection // 使用command.Parameters.Clear()似乎无法解决此问题 // 因此需要深度拷贝 command.Parameters.AddRange(sqlParameters.Select(s => ((ICloneable)s).Clone()).ToArray()); command.CommandText = "SELECT * FROM TABLE WHERE COLUMN = @PARAM AND ... "; // 有些查询语句在SQL Management Studio运行很快,但在代码中会出现超时 // 网上说是因为程序也占用了执行时间 // 这种情况可以添加CommandTimeout command.CommandTimeout = 30000; using (var res = await command.ExecuteReaderAsync()) { while (res.Read()) { // 多任务执行时,插入数据可能会出现数据不一致性问题,就是每次的结果行数不一致 // 使用线程安全先进先出集合,保证数据一致性 queue.Enqueue( new XXX { Column1 = res[0].ToString(), Column2 = res[1].ToString(), Column3 = res[2].ToString(), ... }; ); } } } } } } catch (Exception ex) { throw ex; } }) ); }); // 阻塞主线程,等待所有任务完成 Task.WaitAll(tasks.ToArray()); // 关闭数据库连接 context.Database.CloseConnection(); }
分类:
个人记录
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现