连接释放问题 返回

C#论坛 老数据
41 2242
我在压测数据过程中发现部分连接不释放,修改内容如下,修改后,连接释放。(Mysql 8.0.22)能否关注下,是否有帮助



QueryableProvider.cs

protected ListGetData(KeyValuePair<string, list> sqlObj)
{
    try
    {
        Listresult;
        var isComplexModel = QueryBuilder.IsComplexModel(sqlObj.Key);
        var entityType = typeof(TResult);
        var dataReader = this.Db.GetDataReader(sqlObj.Key, sqlObj.Value.ToArray());
        result = GetData(isComplexModel, entityType, dataReader);
        return result;
    }
    finally
    {
        this.Db.Close();
        this.Db.Dispose();
    }
    
}

protected async Task<list> GetDataAsync(KeyValuePair<string, list> sqlObj)
{
    try
    {
        Listresult;
        var isComplexModel = QueryBuilder.IsComplexModel(sqlObj.Key);
        var entityType = typeof(TResult);
        var dataReader = await this.Db.GetDataReaderAsync(sqlObj.Key, sqlObj.Value.ToArray());
        result =await GetDataAsync(isComplexModel, entityType, dataReader);
        return result;
    }
    finally
    {
        this.Db.Close();
        this.Db.Dispose();
    }
    
}

public virtual DataTable ToDataTable()
{
    try
    {
        InitMapping();
        var sqlObj = this.ToSql();
        RestoreMapping();
        DataTable result = null;
        if (IsCache)
        {
            var cacheService = this.Context.CurrentConnectionConfig.ConfigureExternalServices.DataInfoCacheService;
            result = CacheSchemeMain.GetOrCreate(cacheService, this.QueryBuilder, () => { return this.Db.GetDataTable(sqlObj.Key, sqlObj.Value.ToArray()); }, CacheTime, this.Context);
        }
        else
        {
            result = this.Db.GetDataTable(sqlObj.Key, sqlObj.Value.ToArray());
        }
        return result;
    }
    finally
    {
        this.Db.Close();
        this.Db.Dispose();
    }
}

public async Task<DataTable> ToDataTableAsync()
{
    try
    {
        InitMapping();
        var sqlObj = this.ToSql();
        RestoreMapping();
        DataTable result = null;
        if (IsCache)
        {
            var cacheService = this.Context.CurrentConnectionConfig.ConfigureExternalServices.DataInfoCacheService;
            result = CacheSchemeMain.GetOrCreate(cacheService, this.QueryBuilder, () => { return this.Db.GetDataTable(sqlObj.Key, sqlObj.Value.ToArray()); }, CacheTime, this.Context);
        }
        else
        {
            result = await this.Db.GetDataTableAsync(sqlObj.Key, sqlObj.Value.ToArray());
        }
        return result;
    }
    finally
    {
        this.Db.Close();
        this.Db.Dispose();   
    }
}

AdoAccessory.cs

去除 protected IDbConnection _DbConnection;


AdoProvider.cs

将 AdoAccessory.cs 去除的 ,添加过来
public abstract partial class AdoProvider : AdoAccessory, IAdo
{
    protected IDbConnection _DbConnection;
    #region Constructor



public virtual void Dispose()
{
    if (this.Transaction != null)
    {
        this.Transaction.Commit();
        this.Transaction = null;
    }
    if (this.Connection != null && this.Connection.State != ConnectionState.Open)
    {
        this.Connection.Close();
        this._DbConnection.Close();
    }
    if (this.Connection != null)
    {
        this.Connection.Dispose();
        this._DbConnection.Close();
    }
    this.Connection = null;

    if (this.IsMasterSlaveSeparation)
    {
        if (this.SlaveConnections != null)
        {
            foreach (var slaveConnection in this.SlaveConnections)
            {
                if (slaveConnection != null && slaveConnection.State == ConnectionState.Open)
                {
                    slaveConnection.Dispose();
                }
            }
        }
    }
}

public virtual void Close()
{
    if (this.Transaction != null)
    {
        this.Transaction = null;
    }

    if (this.Connection != null && this.Connection.State == ConnectionState.Open)
    {
        this.Connection.Close();
        this._DbConnection.Close();
    }

    if (this.IsMasterSlaveSeparation && this.SlaveConnections.HasValue())
    {
        foreach (var slaveConnection in this.SlaveConnections)
        {
            if (slaveConnection != null && slaveConnection.State == ConnectionState.Open)
            {
                slaveConnection.Close();
            }
        }
    }
}






热忱回答41

  • 连接释放稳定这了么多年了,可能是你用法问题,

    0 回复
  • 如果有疑问不要轻易乱改代码,你这个代码我就已看出问题几个了,你可以写个控制台DEMO发给我我给你看

    0 回复
  • 我给你讲一下ado连接池机制,你并发请求 连接池不够就会开启多个连接池 每次操作完就会sleep这个连接池并且 下次在有新的请求会判段sleep的连接池是否存在,如果存在用sleep的连接池,连接字符串配置用默认的就好,sqlsugar置成自动释就行了 不建议你改任何一行代码

    0 回复
  • .NET CORE3.0开始GC不会及时回收,你可以设置db.dispose 或者using实现C#对象的内存回收

    0 回复
  • karqical karqical VIP0
    2020/11/23

    我是使用JMeter 进行的压测,我没有使用控制台进行测试。另外,我使用控制台,输出,压测之后,也发现,MySQLCommand 和MysqlConnection 的大量数据,我所说的这些内容都是使用JMeter 进行压测后的结论。image.png

    0 回复
  • @karqical:使用db.dispose就行了 你这个应该是core 3.0以上版本吧

    0 回复
  • .NET CORE 3之后内存回收机质有改动,如果你想手动释放C#内存一定要用 db.dispose或者using(db) 和数据库接池没有一点关系

    image.png

    0 回复
  • 或者按上面设置成 false 也可以不使用db.dispose

    0 回复
  • karqical karqical VIP0
    2020/11/23

    @fate stay night:好的,我先这么配置,再压测,谢谢你的帮助

    0 回复
  • ?下雪? ?下雪? VIP0
    2020/11/23

    这是啥工具啊,这么好用的吗?求透露一下名字

    0 回复
  • ?下雪? ?下雪? VIP0
    2020/11/23

    是他语文没学好吗,,,,咋感觉看起来说的话像机器翻译的。。

    0 回复
  • karqical karqical VIP0
    2020/11/23

    @karqical

    @fate stay night:配置

    falsefalse

    并不起作用,内存依然上升。我想咨询下,SQLSugar 在高并发下,是否适合配置为单例。

    0 回复
  • @karqical:不能单例,你看看 用完 db.dispose有效果没有

    0 回复
  • @karqical:或者我写个代码给你测试一下

    0 回复
  • 你用的是什么数据库我写个代码出来

    0 回复
  • karqical karqical VIP0
    2020/11/24

    @fate stay night:mysql 8.0.22

    0 回复
  • karqical karqical VIP0
    2020/11/24

    @fate stay night:目前代码写成单例的方式,并且我测试过了,正常速度下,是不需要关心内存问题的,只有在频繁调用的时候,或者压测时,这个内存才增长。数据库使用Mysql 8.0.22


    0 回复
  • @karqical:数据库操就不能用单例

    0 回复
  • karqical karqical VIP0
    2020/11/24

    代码已经修改为创建,在单独的控制台测试,没有异常,在RPC 通信中有MysqlCommand 不是放的问题,我再看看

    0 回复
  • @karqical研究一下你那个 RPC 的GC回收机质吧, 只要能够和以前的项目一样像有自带的GC回收机质问题不大

    0 回复
  • karqical karqical VIP0
    2020/11/24
    //sqlCommand.Dispose();

    这里屏蔽掉的原因是什么呢  SqlSugar.AdoProvider.GetDataReaderAsync

    public virtual async Task<IDataReader> GetDataReaderAsync(string sql, params SugarParameter[] parameters)
    {
        try
        {
            Async();
            InitParameters(ref sql, parameters);
            if (FormatSql != null)
                sql = FormatSql(sql);
            SetConnectionStart(sql);
            var isSp = this.CommandType == CommandType.StoredProcedure;
            if (this.ProcessingEventStartingSQL != null)
                ExecuteProcessingSQL(ref sql, parameters);
            ExecuteBefore(sql, parameters);
            var sqlCommand = GetCommand(sql, parameters);
            var sqlDataReader = await sqlCommand.ExecuteReaderAsync(this.IsAutoClose() ? CommandBehavior.CloseConnection : CommandBehavior.Default);
            if (isSp)
                DataReaderParameters = sqlCommand.Parameters;
            if (this.IsClearParameters)
                sqlCommand.Parameters.Clear();
            ExecuteAfter(sql, parameters);
            SetConnectionEnd(sql);
            //sqlCommand.Dispose();
            return sqlDataReader;
        }
        catch (Exception ex)
        {
            CommandType = CommandType.Text;
            if (ErrorEvent != null)
                ExecuteErrorEvent(sql, parameters, ex);
            throw ex;
        }
    }
    0 回复
  • @karqical:考虑到可能是outpust参数之后的东西要返回,所以才去掉了这个代码 让GC去回收

    0 回复
  • 去掉应该是有原因的,具体什么原因我暂时也想不起来

    0 回复
  •  你在测一下和驱动版本有没有关系 

    0 回复
  • karqical karqical VIP0
    2020/11/24

    @fate stay night:可能当时用的Mysql.Data 插件在 8.0.20. 以下,这里使用MysqlCommand.dispose 会报错误(https://bugs.mysql.com/bug.php?id=89159),可能就是这个原因吧。

    0 回复
  • @karqical:时间比较久了不记得了,不过GC回收正常应该可以释放的

    0 回复
  • 我这边在加上去测测

    0 回复
  • @karqical:如果低版本报错的话可能就是那个问题

    0 回复
  • @karqical:新版本优化了一下你试试看

    0 回复
  • @fate stay night:哪个版本开始优化的?

    0 回复
  • karqical karqical VIP0
    2020/11/25

    @fate stay night:很棒,效果很明显,新版中 MysqlCommand 已经自动释放了。剩下就是MySQLConnection 的问题,压测中,发现修改如下代码后,MySQLConnection的溢出不在增长。


    image.png

    SqlSugar.QueryableProvider.GetDataAsync
    
    protected async Task<List<TResult>> GetDataAsync<TResult>(KeyValuePair<string, List<SugarParameter>> sqlObj)
    {
        try
        {
            List<TResult> result;
            var isComplexModel = QueryBuilder.IsComplexModel(sqlObj.Key);
            var entityType = typeof(TResult);
            var dataReader = await this.Db.GetDataReaderAsync(sqlObj.Key, sqlObj.Value.ToArray());
            result =await GetDataAsync<TResult>(isComplexModel, entityType, dataReader);
            return result;
        }
        finally
        {
            this.Db.Close();
            this.Db.Dispose();
        }
    }


    0 回复
  • @karqical:不能这么改的,你用我最新版本测试

    using(sqlsugarclient db=new sqlsugarclient)

    {

       

    }

    或者

    sqlsugarclient db=new sqlsugarclient


    db.dispose

    应该解决了人的问题,哪怕你GC不回收也可以处理


    0 回复
  • @karqical:不要想着改我的代码你这么改是有大问题的 ,最新版本已经按你要求处理过了

    0 回复
  • karqical karqical VIP0
    2020/11/25

    @fate stay night:好的。目前没有改动。

    0 回复
  • karqical karqical VIP0
    2020/11/25

    @fate stay night: 

    更新版本5.0.1.4后,使用如下配置和代码,当字段为 null 会报错:


    /// <summary>
    /// 创建人Id
    /// </summary>
    [SugarColumn(IsNullable =true)]
    public Guid? CreatedUserId { get; set; }
    
    Mysql 字段使用char(36)

    错误为:

    System.AggregateException: One or more errors occurred. (English Message : Entity mapping error.Non-negative number required. (Parameter 'count')
    Chinese Message : 实体与表映射出错。Non-negative number required. (Parameter 'count'))
     ---> SqlSugar.SqlSugarException: English Message : Entity mapping error.Non-negative number required. (Parameter 'count')
    Chinese Message : 实体与表映射出错。Non-negative number required. (Parameter 'count')


    我把 

    Mysql 字段使用varchar(36)

    错误消失。


    或者回退到版本5.0.0.14 这里不需要修改.


    0 回复
  • @karqical:你这个是.NET CORE 5.0才出现的吗?

    0 回复
  • karqical karqical VIP0
    2020/11/26

    @fate stay night:目前我还是用的 .net core 3.1,net core 5.0 还没有试过

    0 回复
  • @karqical:这个问题后面修复

    0 回复
  • @karqical:经过我的测试这个是驱动BUG 暂时不能解决只能等新版本的mysq.data驱动一起更新

      using (var re = Db.Ado.GetDataReader("select * from UnitTAFA1")) 
     {
                    while (re.Read())
                    {
    
                    }
     }

            public class UnitTAFA1

            {

                public string name { get; set; }

                [SugarColumn(IsNullable = true, ColumnDataType = "char(36)")]

                public Guid? a { get; set; }

            }

    .

    0 回复
  • 或者你不插入null

    0 回复
  • karqical karqical VIP0
    2020/11/26

    @fate stay night:为了系统能用,我把数据库 字段是 char36 都改成varchar(36) 了

    0 回复