为了压系统,昨天小组在测试环境模拟了一大批订单数据今天上午查看记录的账单计息日志,发现了一大堆的MySqlException,今天小编就来聊一聊关于static如何用?接下来我们就一起去研究一下吧!
static如何用
为了压系统,昨天小组在测试环境模拟了一大批订单数据。今天上午查看记录的账单计息日志,发现了一大堆的MySqlException
MySql.Data.MySqlClient.MySqlException (0x80004005):
诸如:
2017-01-05 00:40:49.891账单计息异常/{"BillId":1000012082,"OrderId":"DD201701040002672"}:MySql.Data.MySqlClient.MySqlException (0x80004005): There is already an open DataReader associated with this Connection which must be closed first.
通过分析程序,发现dal层的所有方法都是静态的,其中还包括一个静态的db连接对象:
public class BillsDal{ static IDbConnection _conn = ConnUtility.GateWayConntion; /// <summary>
突然想到之前整理的blog《static,你还敢用吗?》,所以,不难分析出来原因:问题就出在这个静态的db连接对象_conn上,因为所有类的实例始终是用一个db连接,当并发出现时,又没有lock数据操作代码,那么,就很容易出现连接在未关闭时又要被建立并打开,这样就出现了db连接异常。
经模拟多线程来测试,的确如此。
问题即答案!修复这个bug的话,有如下2个方案:
-
如果仍然要保留这个static的_conn字段,就要用lock来锁住数据操作代码(GetOrdersBillList),以控制并发冲突
-
每次查询时用一个新的连接对象。
方案分析:第1种,涉及到对象只能在被释放(关闭)掉才能再次被使用(打开),性能低下,不可取。 第2种呢,其实在dal层,绝大多数的程序猿都是按照每一个数据操作只用一个db连接的方式来编码的。 由于大家一般不会把dal类的成员定义成static,所以,也就不会遇到这样的db连接异常。而我呢,倾向于用static方法,考虑到封装,就把这个db连接对象封装成静态字段了,反而忽视了静态数据成员带来的隐患——数据量小时几乎是暴露不出来问题,一旦数据量大起来,有了并发,就会出现资源被同时使用,这样的话,多个线程实例都要修改其状态时,就出现了并发异常。
由此来看,依然用static的话,就要把_conn当做只读的私有属性(不考虑代码味道):
static IDbConnection _conn
这样,当每次访问这个属性时,都会返回一个新的连接对象。
再次模拟多线程测试,ok!
,