老师请教一下,关于单例模式的SqlSugarScope的多线程问题,偶尔报错连接正在被使用 返回
洛阿洛 发布于2025/7/1
下面是注入的代码结构
services.AddScoped(typeof(DataRepository<>));
services.AddScoped(typeof(BaseRepository<>));
services.AddSingleton<ISqlSugarClient>(provider =>
{
var config = new ConnectionConfig
{
ConnectionString = AppSettingHelper.GetDatabaseConnectSettings(),
DbType = DbType.MySql,
IsAutoCloseConnection = true
};
return new SqlSugarScope(config);
}
);
services.AddDataBase("TL.Database", ServiceLifetime.Scoped); public class BaseRepository<T> where T : class, new()
{
/// <summary>
/// 数据库连接的对象变量
/// </summary>
private DataRepository<T>? _dbRepository;
/// <summary>
/// 构造函数的参数为数据库连接对象
/// </summary>
/// <param name="dbrepository"></param>
public BaseRepository(DataRepository<T> dbrepository)
{
this._dbRepository = dbrepository;
}
public DataRepository<T>? DbRepository
{
get => this._dbRepository;
set => this._dbRepository = value;
}
} public class DataRepository<T> : SimpleClient<T> where T : class, new()
{
public DataRepository(ISqlSugarClient context) : base(context)
{
base.Context = context;
}
} public class AlarmCodeDao : BaseRepository<AlarmCode>, IAlarmCodeDao
{
public AlarmCodeDao(DataRepository<AlarmCode> dbrepository) : base(dbrepository)
{
}
/// <summary>
/// 获取所有告警分类标识记录
/// </summary>
/// <returns></returns>
public List<AlarmCode> GetAlarmCodeEntities()
{
return DbRepository.GetList().ToList();
}
public AlarmCode GetAlarmCodeById(string id)
{
return DbRepository.GetById(id);
}
public bool InsertAlarmCode(AlarmCode alarmCode)
{
return DbRepository.Insert(alarmCode);
}
public bool UpdateAlarmCode(AlarmCode alarmCode)
{
return DbRepository.Update(alarmCode);
}
public bool DeleteAlarmCodeById(string id)
{
return DbRepository.DeleteById(id);
}
}程序是上位机程序,使用Task.Run()开了几个线程在后台运行控制多个下位机,并在动作完成后更新数据库,控制下位机会使用异步方法,控制完成后使用注入的数据仓库更新数据
控制的伪代码大概是Task.run(async() =>{while(true){ //根据信息运行不同的动作 await TakeTubeAsync(); //更新数据库 alarmDao.update() }} ),控制线程基本都是这样
求老师帮忙解惑
热忱回答(5)
-
fate sta VIP0
2025/7/1SqlSugarScope 模式 (性能中上)
只需要看下面3条就行了,100%覆盖所有场景
1、异步方法wait存在漏写, 一个不能少 。解决方案:找到漏掉的await 建议补上遗漏的await,如果不想补就用db.CopyNew()。
2、使用await 返回值必须有Task,不能是Void 这种(表达式中异步只能是Func<Task>不能是Action<X> ,比如List.Forech就是Action要改普通forech) 建议改代码,如果不想修改 db改成db.CopyNew()解决
3、Task.WhenAll 、 ParallelAsync 和 第三方定时任务库 Job (backgroundservice也算) 使用 db.CopyNew()
注意1: CopyNew只有定时任务和Task.WhenAll 第3项必要需要加其他只要代码写对就不需要加
注意2: CopyNew要当前业务方法用,不能赋值全局变量,避免写到公用方法(会破坏事务会有问题)
注意3: CopyNew如果要用事务看3.1
注意4:多租户要用db.CopyNew().GetConnection方法(不能用GetConnectionScope)
目前就几种情况
0 回复 -
fate sta VIP0
2025/7/1因为我看不到你的代码,如果你不会解决
可以这么写强制线程安全。
Task里面可以这么写
db.CopyNew().Insertable(xx)....
用copynew强制线程安全
0 回复 -
fate sta VIP0
2025/7/1或者你提供一个可以重现的DEMO
0 回复 -
洛阿洛 VIP0
2025/7/2问题解决了,尝试写复现demo的时候怎么也复现不了,但是同事那可以,对比看了一下是因为,同事的代码在使用Task.Run开启线程前,使用注入的数据仓库更新了一下数据,把更新数据的那一条删除掉就好了,我们开发的是winform程序,在程序上点击按钮后触发几个Task.Run线程控制下位机并更新数据库,我同事是因为在开启线程前使用注入的数据仓库更新了一下数据库就导致了问题。不过有点想不明白为什么会有这种问题
0 回复 -
fate sta VIP0
2025/7/2@洛阿洛:不清楚你的代码,需要提供完整测试用例
0 回复