例如,下面一段代码,当两个线程同时访问时会出现各种由于线程不同步而导致的问题,比如什么DataReader已打开未关闭啊,已经添加了重复的键啊等等。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /// <summary> 2 /// 当前数据上下文,非线程安全 3 /// </summary> 4 static AouUnionPayDataContext db = new AouUnionPayDataContext(connStr); 5 6 /// <summary> 7 /// 此处是并发发生错误的方法,当两个线程访问时会出错 8 /// </summary> 9 /// <typeparam name="T">查找的实体对象类型</typeparam> 10 /// <param name="predicate">查找的条件,linq to sql语法</param> 11 /// <returns></returns> 12 public T GetSingle(Expression<Func<T, bool>> predicate) 13 { 14 return db.GetTable<T>().SingleOrDefault(predicate); 15 }
主要问题在于,多线程情况下同时访问db对象,拿到db对象执行GetTable<T>()方法会出错,相当于都在使用同一个数据库DataReader。这种情况是不允许的。
当项目中很多地方都使用了db此对象,而所有的db都只允许单一线程进行操作时,这时候在代码段头尾加上lock(db){}是不够的。
可以考虑将db封装为线程安全对象,如以下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /// <summary> 2 /// 当前数据上下文,非线程安全 3 /// </summary> 4 static AouUnionPayDataContext db = new AouUnionPayDataContext(connStr); 5 6 /// <summary> 7 /// 线程安全的数据库访问对象 8 /// </summary> 9 protected static AouUnionPayDataContext db_safe 10 { 11 set 12 { 13 lock(db) 14 { 15 db = value; 16 } 17 } 18 get 19 { 20 lock(db) 21 { 22 return db; 23 } 24 } 25 } 26 27 /// <summary> 28 /// 使用了线程安全对象 29 /// </summary> 30 /// <typeparam name="T">查找的实体对象类型</typeparam> 31 /// <param name="predicate">查找的条件,linq to sql语法</param> 32 /// <returns></returns> 33 public T GetSingle(Expression<Func<T, bool>> predicate) 34 { 35 return db_safe.GetTable<T>().SingleOrDefault(predicate); 36 }