现在我使用一个简单的SQL语句的某张表的数据,但是这张表中有CLOB字段,这时会发现此应用程序有内存泄漏,不知有没有什么好办法可以解决!

解决方案 »

  1.   

    我这儿就放一段访问数据库的代码吧!其中m_strSql是界面录入的SQL语句,如果SQL语句中不含CLOB字段是没有一点内存泄漏,但是只要有CLOB字段就会出现分配的类春不能完全释放 for(long i= 0;i < 10;i++)
    {
    CComBSTR bstrSql;
    _RecordsetPtr spAdoRs;
    try
    {
    HRESULT hr = spAdoRs.CreateInstance(__uuidof(Recordset));
    if(FAILED(hr)) continue;
    spAdoRs->PutCursorLocation(adUseClientBatch);
    bstrSql = m_strSql;
    spAdoRs->Open((BSTR)bstrSql, m_spAdoCon.GetInterfacePtr(), adOpenStatic, adLockBatchOptimistic, -1);
    }
    catch(_com_error e)
    {
    CString str,strMsg;
    str = (BSTR)e.Description();
    strMsg.Format(_T("错误号:%d,错误原因:%s"),e.Error(),str);
    MessageBox(strMsg);
    return ;
    }
    }
    return ;
      

  2.   

    m_spAdoCon是当前的数据库连接对象!
      

  3.   

    CLOB字段最好用GetChunck的方式一段一段的取
      

  4.   

    ESULT hr = m_pRecordset->Open("SELECT * FROM userphoto",_variant_t((IDispatch *)theApp.m_pConnection,true),adOpenDynamic,adLockPessimistic,adCmdText);
      

  5.   

    经过一段时间的仔细琢磨终于找到了解决办法。就是采用_CommandPtr接口的Execute方法,设置一定的参数就可以不内存泄漏!但是Execute方法默认返回的结果集是悲观锁方式的,由于我的程序是放在COM+中运行的所以必须要是乐观锁批更新方式(adLockBatchOptimistic)的锁的结果集才能在客户端进行修改。所以有什么办法可以让Execute方法返回的结果集是以adLockBatchOptimistic锁的!对于采用创建一个新的结果集的方式就不用说了,因为那种方式较慢。谢谢大家的支持!
      

  6.   

    我也遇到一个问题使用如下办法取的Recordset不会有内存泄漏但是此时的Recordset是只读的
    STDMETHODIMP GetRecordset(BSTR bstrSQL, _Recordset **ppRs)
    {
    HRESULT hr;
    VARIANT var;
    long lCount = 0;
    _CommandPtr spAdoCmd = NULL;
    _ParameterPtr spAdoClob = NULL;
    _RecordsetPtr spAdoRs = NULL;
    VariantInit(&var);
    try
    {
    m_spAdoCon->PutCursorLocation(adUseClient);
    hr = spAdoCmd.CreateInstance(__uuidof(Command));
    if(FAILED(hr)) return hr;
    spAdoCmd->ActiveConnection = m_spAdoCon;
    spAdoClob = spAdoCmd->CreateParameter(L"prCLOB",adLongVarChar,adParamOutput,100000);
    hr = spAdoCmd->Parameters->Append(spAdoClob);
    spAdoCmd->Properties->GetItem(L"SPPrmsLOB")->Value = 1L; spAdoCmd->CommandText = bstrSQL;
    spAdoRs = spAdoCmd->Execute(&var,NULL,adCmdText); var.vt = VT_DISPATCH;
    var.pdispVal = NULL;
    spAdoRs->PutActiveConnection(var);
    *ppRs = spAdoRs.Detach();
    VariantClear(&var);
    }
    catch(_com_error e)
    {
    //异常处理
    }
    return S_OK;
    }
    用如下的办法得到的Recordset是可写的,但是会产生内存泄漏
    STDMETHODIMP GetRecordset(BSTR bstrSQL, _Recordset **ppRs)
    {
    HRESULT hr;
    VARIANT var;
    long lCount = 0;
    _CommandPtr spAdoCmd = NULL;
    _ParameterPtr spAdoClob = NULL;
    _RecordsetPtr spAdoRs = NULL;
    VariantInit(&var);
    try
    {
    m_spAdoCon->PutCursorLocation(adUseClient);
    hr = spAdoCmd.CreateInstance(__uuidof(Command));
    if(FAILED(hr)) return hr;
    spAdoCmd->ActiveConnection = m_spAdoCon;
    spAdoClob = spAdoCmd->CreateParameter(L"prCLOB",adLongVarChar,adParamOutput,100000);
    hr = spAdoCmd->Parameters->Append(spAdoClob);
    spAdoCmd->Properties->GetItem(L"SPPrmsLOB")->Value = 1L; spAdoCmd->CommandText = bstrSQL;
    hr = spAdoRs.CreateInstance(__uuidof(Recordset));
    if(FAILED(hr)) return hr;
    spAdoRs->PutCursorLocation(adUseClientBatch);
    spAdoRs->Open((IDispatch *)spAdoCmd, vtMissing, adOpenStatic, adLockBatchOptimistic, -1); var.vt = VT_DISPATCH;
    var.pdispVal = NULL;
    spAdoRs->PutActiveConnection(var);
    *ppRs = spAdoRs.Detach();
    VariantClear(&var);
    }
    catch(_com_error e)
    {
    //异常处理
    }
    return S_OK;
    }
    说明对于此语句只能是使用ORACLE数据库才可运行,因为有它的专用属性SPPrmsLOB及专用参数。
    希望大家帮忙,至于分的问题不是问题。
      

  7.   

    至于产生内存泄漏的地方不是别的地方,正是产生Recordset的地方。对于Oracle的OleDB说的是需要指定使用的SQL语句中有LOB字段,并指定绑定变量需要分配多大的空间,这样才是问题的解决的真正办法,但是一旦使用命令参数就出现上面的问题。注如果使用服务器游标是没有内存泄漏的但是不满足我使用的环境,因为我是在专用的COM+数据库连接池中使用,所以必须把无连接的Recordset返回给调用者。
      

  8.   

    一些特殊字段,比如存储的图片信息,一般用GetChunk()来取,用AppendChunk()来存。
      

  9.   

    现在的问题不是在于怎样在Recordset中怎样取数据,而是采用客户端游标的情况下使用Recordset查询数据就有内存泄漏。当然ORACLE的解决办法是提示取数的绑定变量地方申请一个缓冲区就可以了,但是采用命令的方式使用Recordset的OPEN方法好像设置的参数不起作用,只有采用_CommandPtr的Execute方法设置的参数才起作用。但是ado好像又没有任何地方提示需要怎么做!
      

  10.   

    有什么办法能让只读的Recordset变成可以保存数据的Recordset,各种方式都可以。但是使用_CommandPtr的Execute方法查询得到的Recordset的信息不全!