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();
}