In order to press the system, the team simulated a large number of order data in the test environment yesterday. Check out the recorded bill this morning and find a whole bunch of mysqlexception
MySql.Data.MySqlClient.MySqlException (0x80004005): There is already a open DataReader associated with this Connection wh Ich must be closed first.
Such as:
2017-01-05 00:40:49.891 Bill interest Anomaly/{"billID": 1000012082, "OrderId": "DD201701040002672"}: MySql.Data.MySqlClient.MySqlException (0x80004005): There is already a open DataReader associated with this Connection wh Ich must be closed first. In MySql.Data.MySqlClient.ExceptionInterceptor.Throw (Exception Exception) in MySql.Data.MySqlClient.MySqlCommand.Throw (Exception ex) in MySql.Data.MySqlClient.MySqlCommand.ExecuteReader ( CommandBehavior behavior) in MySql.Data.MySqlClient.MySqlCommand.ExecuteDbDataReader (CommandBehavior behavior) in System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader (CommandBehavior behavior) in Commonlibrary.commonorm.commonorm_dapper.<queryimpl>d__11 ' 1.MoveNext () position e:\work\yijia\trunk\ Commonlibrary\commonorm\commonorm_dapper.cs: line number 1554 at System.Collections.Generic.List ' 1..ctor (IEnumerable ' 1 Collection) in System.linq.enumerable.tolist[tsource] (IEnumerable ' 1 source) in CommonLibrary.CommonOrm.CommonOrm_ Dapper.query[t] (idbconnection CNN, String SqL, Object param, idbtransaction transaction, Boolean buffered, Nullable ' 1 commandtimeout, Nullable ' 1 commandtype) location E:\wo Rk\yijia\trunk\commonlibrary\commonorm\commonorm_dapper.cs: line number 1444 in GateWay.DAL.BillsDal.BillsDal.GetOrdersBillList (String bizorderid) position e:\work\yijia\trunk\GetWay.DAL\BillsDal\ BillsDal.cs: line number 123 in GateWay.BLL.Bills.BillsBll.GetOrdersBill (String Bizorderid, billtypeenum billtype) Location E:\work\ Yijia\trunk\getway.bll\bills\billsbll.cs: Line number 27 in GateWay.BLL.Bills.PrincipalBillsInterest.InterestBill (t_bills Principlebill) Location E:\work\yijia\trunk\GetWay.BLL\Bills\PrincipalBillsInterest.cs: line number 186 in GateWay.BLL.Bills.PrincipalBillsInterest.Interest () Location e:\work\yijia\trunk\GetWay.BLL\Bills\ PrincipalBillsInterest.cs: Line No. 77
Through the parser, all the methods of the DAL layer are found to be static, including a static DB connection object:
Public classbillsdal{StaticIDbConnection _conn =connutility.gatewayconntion; /// <summary> ///get all bills for a specified business order (by merchant Code and order number)/// </summary> /// <param name= "Bizorderid" >Order ID, unique</param> /// <returns></returns> Public StaticList<t_bills> Getordersbilllist (stringMercode,stringBizorderno) { varobj = _conn. Query<t_bills> ("SELECT * from T_bills where mercode= '"+ Mercode +"' and orderno= '"+ Bizorderno +"'"); returnobj. ToList (); }}
Suddenly think of the previous tidy blog "Static, you dare to use it?" , so, it is not difficult to analyze the reason: The problem is on this static DB connection object _conn, because all instances of the class is always a DB connection, when the concurrency occurs, and there is no lock data operation code, then it is easy to appear when the connection is not closed and will be built and opened, The DB connection exception occurs.
Tested by analog multithreading, that's true.
The question is the answer! To fix this bug, there are 2 scenarios:
- If you still want to keep this static _conn field, lock the data Manipulation code (getordersbilllist) to control concurrency conflicts
- A new Connection object is used each time the query is made.
Scenario Analysis: The 1th, involving the object can only be released (closed) off to be used again (open), poor performance, undesirable. The 2nd kind, in fact, in the DAL layer, the vast majority of the program apes are in accordance with each data operation only a DB connection way to encode. Since members of the Dal class are generally not defined as static, there is no such thing as a DB connection exception. And I, inclined to use the static method, considering the encapsulation, the DB connection object is encapsulated into a static field, instead of ignoring the static data members of the hidden danger-the data volume of the hour is almost not exposed to the problem, once the data volume is large, with concurrency, there will be resources are used simultaneously, so that, When multiple thread instances are modifying their state, a concurrency exception occurs.
From this point of view, still using static, it is necessary to treat _conn as a read-only private property (regardless of the code flavor):
Static IDbConnection _conn { getreturn connutility.gatewayconntion;} }
This will return a new connection object each time the property is accessed.
Simulate multithreaded testing again, ok!
Static, do you dare to use it? Two