有什么办法能解决使用ADO访问ORACLE数据库的CLOB字段的有内存泄漏问题?

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

14 个解决方案

#1


你把程序代码放上来看一下,不是数据库问题,是代码问题

#2


内存泄漏常见的情况,
应该与数据库操作没有关系。

#3


我这儿就放一段访问数据库的代码吧!其中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 ;

#4


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

#5


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

#6


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

#7


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

#8


学习

#9


我也遇到一个问题使用如下办法取的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及专用参数。
希望大家帮忙,至于分的问题不是问题。

#10


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

#11


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

#12


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

#13


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

#14


呵呵,我自己来UP一下!希望大家能到这儿来发表自己的看法。谢谢。

#1


你把程序代码放上来看一下,不是数据库问题,是代码问题

#2


内存泄漏常见的情况,
应该与数据库操作没有关系。

#3


我这儿就放一段访问数据库的代码吧!其中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 ;

#4


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

#5


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

#6


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

#7


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

#8


学习

#9


我也遇到一个问题使用如下办法取的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及专用参数。
希望大家帮忙,至于分的问题不是问题。

#10


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

#11


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

#12


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

#13


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

#14


呵呵,我自己来UP一下!希望大家能到这儿来发表自己的看法。谢谢。