我的程序用的是VC+ADO访问Oracle数据库,程序运行一段时间就会报出ORA-01000: 超出打开游标的最大数错误。我在数据库中查看了当前打开的游标,我的程序打开的游标都关闭了,不知道问题出在哪里,请指教
下面附上出问题的代码段
BOOL #######::*******(CString PartCode,CString FaultCode,int FaultNO,CString FilePath,int ImgNO)
{

CFile infile;
CString Postion[4],strFindTime;
CString strTrainSerial,strVehicleSerial;
BOOL bRet = FALSE; //检查数据库连接是否正常
if (!g_DB_Recong.CheckDBConn())
{
WriteTFDSLog("数据库连接断开,重新连接数据库!");
bRet = g_DB_Recong.ReConnect(g_pDlg->m_sService,g_pDlg->m_sUserID,g_pDlg->m_sUserPwd);
if (!bRet)
{
WriteTFDSLog("重连数据库失败!");
return FALSE;
}
} if(g_Gmc)
{
strTrainSerial = g_pDlg->m_RecongData[0].TrainSerial;
strVehicleSerial = g_pDlg->m_RecongData[0].VehicleSerial;
}
else
{
strTrainSerial = g_pDlg->m_OtherRecongData[0].TrainSerial;
strVehicleSerial = g_pDlg->m_OtherRecongData[0].VehicleSerial;
} Postion[0].Format("%d",m_FaultRect.left);
Postion[1].Format("%d",m_FaultRect.right);
Postion[2].Format("%d",m_FaultRect.top);
Postion[3].Format("%d",m_FaultRect.bottom); try
{
infile.Open(FilePath,CFile::modeRead|CFile::typeBinary);
}
catch (_com_error err)
{
g_DB_Recong.write_com_error("打开文件失败!",err);
return FALSE;
}
long nSize = infile.GetLength(); CTime time = CTime::GetCurrentTime();
strFindTime = time.Format("%Y-%m-%d %H:%M:%S"); CString strSql;
CADORecordset* pRs = new CADORecordset(g_DB_Recong.m_pDB);
if(pRs == NULL)
{
WriteTFDSLog("创建记录集失败!");
return FALSE;
} try
{
strSql.Format("insert into tf_******_auto(TRAIN_SERIAL,VEHICLE_SERIAL,FAULT_NUMBER,FAULT_PLACE,FAULT_ID, \
DETECTOR, DETECT_TIME, FOUND_MODE,PONDERANCE, POSITION_LEFT, POSITION_RIGHT, POSITION_TOP,POSITION_BOTTOM,IMG_LENGTH,IMG_INDEX) \
values('%s','%s','%d','%s','%s','%s',to_date('%s','yyyy-mm-dd hh24:mi:ss'),'%s','%s','%s','%s','%s','%s','%d','%d')",
strTrainSerial,
strVehicleSerial,
FaultNO,
PartCode,
FaultCode,
"计算机",
strFindTime,
"1",
"0",
Postion[0],
Postion[1],
    Postion[2],
Postion[3],
nSize,
ImgNO);

WriteTFDSLog("打开记录集");
if (!pRs->Open((LPCTSTR)strSql))
{
// 关闭记录集,释放空间
if(pRs != NULL)
{
pRs->Close();
WriteTFDSLog("关闭记录集");
}
delete pRs;
pRs = NULL;
    WriteTFDSLog("故障信息写数据库失败!"); return FALSE;
}
else
{
WriteTFDSLog("故障信息写数据库成功!");
}
// 关闭记录集,释放空间
if(pRs != NULL)
{
pRs->Close();
WriteTFDSLog("关闭记录集");
}
}
catch (_com_error err) 
{
CString strMsg;
strMsg = _T("插入故障信息出错");
g_DB_Recong.write_com_error(strMsg,err);
if (pRs != NULL)
{
pRs->Close();
delete pRs;
pRs = NULL;
}
return FALSE;
} try
{
WriteTFDSLog("故障图片入库");
CString strFaultNO;
strFaultNO.Format("%d",FaultNO);
strSql = "select IMG_DATA from tf_******_auto  \
where TRAIN_SERIAL = '" + strTrainSerial
+ "' and VEHICLE_SERIAL = '" + strVehicleSerial + "' and FAULT_NUMBER =" + strFaultNO;

if (pRs->Open((LPCTSTR)strSql))
{
WriteTFDSLog("打开记录集");
//按文件的大小在堆上申请内存块
BYTE * pBuffer = new BYTE [nSize];

//把jpg文件读到pBuffer
if (infile.Read(pBuffer, nSize) > 0 )

BOOL  bRet;
bRet = pRs->AppendChunk("IMG_DATA",pBuffer,nSize);
if (!bRet)
WriteTFDSLog("AppendChunk() 执行失败"); bRet = pRs->Update();
if(!bRet)
WriteTFDSLog("Update() 执行失败"); infile.Close();
WriteTFDSLog("读图像文件数据入缓存成功");
}
else
{
WriteTFDSLog("读图像文件数据入缓存失败");
return FALSE;
}
//删掉堆上申请的内存
delete [] pBuffer;
pBuffer = NULL;
WriteTFDSLog("释放内存成功"); // 关闭记录集,释放空间
if(pRs != NULL)
{
pRs->Close();  //出问题都是在执行这句的时候进入异常之后执行close还是失败
WriteTFDSLog("关闭记录集0");
}
WriteTFDSLog("关闭记录集成功");
}
else
{
if(pRs != NULL)
{
pRs->Close();
WriteTFDSLog("关闭记录集00");
}
delete pRs;
pRs = NULL;
return FALSE;
}
}
catch (_com_error err) 
{
CString strMsg;
strMsg = _T("插入故障信息出错");
g_DB_Recong.write_com_error(strMsg,err);
// 关闭记录集,释放空间
if (pRs != NULL)
{
pRs->Close();
delete pRs;
pRs = NULL;
}
return FALSE;
}

delete pRs;
pRs = NULL; return TRUE;

请高手帮忙,问题解决在奉上100分。

解决方案 »

  1.   

    open_max_cursor 已经设置成300了,这个不是解决问题的根本原因。
      

  2.   

    Oracle中,任何sql查询都是Cursor,不光是你显式定义的。这些cursor会一直"存活"直到session断开。如果这些cursor都是你的程序必须的,那增大Oracle初始化参数OPEN_CURSORS能解决这个问题。
      

  3.   

    AskTom上不错的一篇介绍OPEN_CURSORS的文章,不过是英语的。You have to consider all cursors -- cursors you open, cursors your application framework 
    will open on your behalf, cursors the database must open to perform recursive SQL.For example, if you are in forms and have a default block and nothing else and run that 
    form, you'll find (before doing ANYTHING) you have some cursors open.  Forms (your 
    application framework) has done some sql and cached the cursors on your behalf.As you do more work in forms (eg: query up a row, update a field in the row) you'll see 
    more and more cursors appear.  Some you opened (by doing the query).  Others were opened 
    on your behalf (eg: forms locking the record for us when we updated the field).You might also see some cursors come and go that reference SYS tables.  These would be 
    recursive queries and would happen when the optimizer parses your query, needs to 
    allocate space for your query and so on.You might also see other cursor come into play when triggers fire, stored procedures run 
    and so on.
    It is not possible for 2 sessions to share the same exact cursor but it is highly 
    probable that 2 sessions will share the same "shared_pool" entry for the underlying query 
    (see SHARED SQL in the concepts guide).  A cursor is in your space, the parse tree, 
    optimization, security and such is in a shared space.It should be noted that OPEN_CURSORS simply allocates a fixed number of slots but does 
    not allocate memory for these slots for a client (eg: it sets an array up to have 1,000 
    cursors for example but does not allocate 1,000 cursors).  Rather, we will allocate 64 
    cursor contexts at a time, as needed (so the first cursor will allocate 64 contexts, the 
    65'th will get 64 more and so on).   So, setting open-cursors to 1,000 or so it not 
    harmful (but don't go overboard and set it to 1,000,000 or something ;) 我通常OPEN_CURSORS会设置为1500或者更大。
      

  4.   

    是不是你的程序中,有些游标没有关闭。
    还有就是关闭游标的操作要放到finally里面。
      

  5.   

    VC中没有finally   我的程序中每次打开游标之后都有关闭的。
      

  6.   

    那还是考虑一下增加cursor吧。但是相应的sharedpool也可能要增加。
      

  7.   

    以前遇到类似问题,不要把OPEN CURSOR放在循环里,自己好好检查一下你的程序。