当负载增加时,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, Action2 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, Nullable1 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 - 因此共享 - 连接(即使它没有显示,我们可以假设_oracleConnectionstatic,因为它是从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 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

浅谈SpringCloud Ribbon负载均衡

Nginx实现负载均衡的方式

负载均衡的实现

Nginx实现负载均衡的方式有哪几种呢?

Nginx实现负载均衡

负载测试中崩溃点和降级之间的差异