当负载增加时,Dapper 崩溃
Posted
技术标签:
【中文标题】当负载增加时,Dapper 崩溃【英文标题】:Dapper is crashing when load is increased 【发布时间】:2021-11-14 23:47:05 【问题描述】:我在基于 .net 5.0 的支付处理应用程序中使用 dapper。在单元测试中,一切正常,但是当我使用 JMeter 加载 100 个用户的负载时,在处理少量事务后,dapper 开始崩溃并出现以下错误:
异常[System.InvalidOperationException:必须打开连接 对于这个操作 Oracle.ManagedDataAccess.Client.OracleCommand.ValidateStatePriorToExecution() 在 Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteNonQuery() 在 Dapper.SqlMapper.ExecuteCommand(IDbConnection cnn, CommandDefinition& command, Action
2 paramReader) in /_/Dapper/SqlMapper.cs:line 2822 at Dapper.SqlMapper.ExecuteImpl(IDbConnection cnn, CommandDefinition& command) in /_/Dapper/SqlMapper.cs:line 572 at Dapper.SqlMapper.Execute(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Nullable
1 commandTimeout, Nullable`1 commandType) 在 /_/Dapper/SqlMapper.cs:line 443
SP执行代码如下:
public static int ExecuteSP(string spName, object parameters)
IDbConnection connection = ConnectionManager.GetConnection(_ConnectionString);
int result = connection.Execute(spName, parameters, null, null, CommandType.StoredProcedure);
ConnectionManager.CloseConnection();
return result;
public static IDbConnection GetConnection(string connectionString)
DefaultTypeMap.MatchNamesWithUnderscores = true;
if (_oracleConnection == null)
_oracleConnection = new OracleConnection(GetConnectionString(connectionString));
if (_oracleConnection.State == ConnectionState.Closed)
_oracleConnection.Open();
return _oracleConnection;
我在配置或使用 Dapper 时有什么遗漏吗?
【问题讨论】:
【参考方案1】:这里的错误是使用static
- 因此共享 - 连接(即使它没有显示,我们可以假设_oracleConnection
是static
,因为它是从static
方法@987654325 访问的@)。
连接不是线程安全的,通过将其设为static
,您的所有代码都共享一个连接。这往往会扩展到恰好一个用户,即一个并发请求 - 在此之上:几乎可以保证失败。
连接的范围应该是一段逻辑代码——它可以是“单个方法”到“整个请求”之间的任何地方,但它们必须一次由一个线程访问.您还应确保在离开该范围时正确处理连接,以防止连接泄漏。
(顺便说一句:问题与 Dapper 并没有真正的关系;任何类似的用法都会出现完全相同的问题 - 无论是 ADO.NET、Dapper、EF 还是其他任何东西)
【讨论】:
我想分离包含所有查询执行方法的数据库管理器类。这些方法将从需要数据的不同类中调用。但我面临的问题是 connection.Query 或 connection.QueryMultiple 函数返回的数据只有在连接打开之前才能访问。但是我想对这些方法做一个通用的实现。有什么建议吗? @ShaziaTabassum 这里唯一的问题是静态连接;其他一切都很好;一个简单的解决方法是完全丢弃连接字段,每次都从连接字符串中新建一个(您可以将 that 存储在静态字段中 - 那就是很好)- 即using var conn = new SqlConnection(s_ConnectionString);
(如果您使用的是早期的 C# 版本,则与“使用块”类似)- 但是每次调用数据访问层,这样连接是本地的; “连接池”将使它仍然很快,等等
看下面的方法,如果我在这里关闭连接,我会丢失'parameters'变量中接收到的输出值:public static void GetOutputParameters(string spName, object parameters) IDbConnection connection = new OracleConnection(_connectionString); connection.Query(spName, param: parameters, commandType: CommandType.StoredProcedure); //connection.Close();
@Shazia 我不清楚你的意思是什么——另外,应该是Execute
,而不是Query
,因为你没有使用结果。关闭连接在那里几乎没有什么区别,除非你做的事情非常不寻常
实际上我在调用者方法中使用了它的结果。并希望这个 GetOutputParameter 方法是通用的,以便可以从多个类中调用它。但是如果我在这里关闭连接,我将无法在调用者方法中使用结果。如果我不关闭连接,就会有连接泄漏以上是关于当负载增加时,Dapper 崩溃的主要内容,如果未能解决你的问题,请参考以下文章