偶发性错误

这种错误并不是每次都能重现,当遇到偶尔发生的错误,99%是因为线程安全问题引起的,我把这些客户出现错误的代码进行了分类和整理


1、用到IOC的情况

自带 IOC  正确用法             http://www.codeisbug.com/Home/Doc?typeId=1211 

AutoFac IOC   正确用法     http://www.codeisbug.com/Home/Doc?typeId=1223  



2、没用到IOC ,一般有3种情况

2.1 因为 SqlSugarClient 对象给单例或者静态引起的

//正确用法
public static SqlSugarClient db
{
    get
    {
        return new SqlSugarClient(new ConnectionConfig()
        {
            DbType = DbType.SqlServer,
            ConnectionString = Config.ConnectionString,
            InitKeyType = InitKeyType.Attribute,
            IsAutoCloseConnection = true
        });
    }
}

//用的时候需要注意因为每次执行到db都会new出一次新对象
var mydb=db;//正确使用,防止多次new
db.xxx
db.xxxxx
   
        
//错误用法 
public static SqlSugarClient db =  new SqlSugarClient(new ConnectionConfig()
{
            DbType = DbType.SqlServer,
            ConnectionString = Config.ConnectionString,
            InitKeyType = InitKeyType.Attribute,
            IsAutoCloseConnection = true,

});
//无论如何用都是错误的


2.2 SqlSugarClient 跨线程使用引起的,保证一个线程new出一个新的SqlSugarClient实例

//正确用法
Task.Run(() =>
{
    var db = new SqlSugarClient(..);//保证线程唯一
    var query2 = db.Queryable<Order>().Where(it => it.Id == 1);

});

//错误用法
Task.Run(() =>
{
        //db已经跨线程了
    var query2 = db.Queryable<Order>().Where(it => it.Id == 1);

});


2.3 继承引起的单例

//错误用法
public class Worker:DbContext
{
    public void Test()
    {
       Db.xxxxx
       Db.xxxx
    } 
}
public class DbContext
{
   public SqlSugarClient Db;
   public DbContext(){
      Db=new SqlSugarClient(....);
   }
}
public class  WorkerBLL
{
  public static Worker worker=new Worker(); //当Worker给静态后 db也给变相的静态了
 
}
注意如果Worker没给单例,但是WorkerBLL给单例也会出现问题,也就是说只要继承关系最上层有一个单例全部出错
   
//正确用法 
public class DbContext
{
   public SqlSugarClient Db 
   get{
       
      return new SqlSugarClient(...);//每调用Db都会new一个新的SqlSugarClient
   }
    
}
public class Worker:DbContext
{
    public void Test()
    {
       var db=Db;//传给变量不然每次执行Db都会new
       db.xxxxx
       db.xxxx
    } 
}


3、异步引起的线程问题

首先你要保证上面的1和2没有问题,才能看下面的问题

//错误用法
public async Task<List<Order>> Test()
{
    var db = GetInstance();

    await GetAsync();

    //在task出现另开线程这种db就跨了线程,task里面的db必须new出来
    await new Task(() => { db.Queryable<OrderItem>().ToListAsync(); });

    return await db.Queryable<Order>().ToListAsync();
}


//错误用法
public async Task<List<Order>> Test()
{
    var db = GetInstance();

    await GetAsync();

    var list= db.Queryable<Order>().ToListAsync().Result;//.Result或者.Await()都会阻塞当前线程

    return await db.Queryable<Order>().ToListAsync();
}


//正确用法 每个异步方法都用await进行串起来
public  async Task<List<Order>> Test()
{
    var db = GetInstance();

    await GetAsync();

    await db.Queryable<OrderItem>().ToListAsync();

    return await db.Queryable<Order>().ToListAsync();
}


4、反射动态调用多个程序集引起的偶发性错误

一般会报找不到XXX类

需要每次创建db的时候加上 Db.InstanceFactory.RemoveAllCache();


5、手动修改数据库表结构,没有重启IIS程序

因为查询会缓存数据绑定方法,你表结构不同了这个缓存的绑定实体方法就报错了