两天前写的一篇文章提到公司的应用程序常常出现ORA-21500错误(http://blog.csdn.net/ah__fu/archive/2008/04/16/2296641.aspx),在网上找了很久,终于有以下资料提供了些头绪:
http://www.dbatools.net/doc/bug10204.html Bugs fixed in the 10.2.0.4 Patch Set
http://blogs.sun.com/mandalika/tags/oracle Solaris/SPARC: Oracle 11gR1 client for Siebel 8.0
从BLOG http://blogs.sun.com/mandalika/tags/oracle 的最后几句话:
Although I'm not sure what exactly is the underlying issue for the core dump, my suspicion is that there is some memory corruption in Oracle client's code; and the Siebel Object Manager crash is due to the Oracle bug 5682121 - Multithreaded OCI clients do not mutex properly for LOB operations. The fix to this particular bug would be available in Oracle 10.2.0.4 release; and is already available as part of Oracle 11.1.0.6.0. In case if you notice the symptoms of failure as described in this blog post, upgrade the Oracle client in the application-tier to Oracle 11gR1 and see if it brings stability to the Siebel environment. |
得知,这个专家认为这个错误是ORACLE客户端的BUG导致的,必须要将客户端升级到ORACLE 10G才能解决。(P.S 公司使用的ORACLE版本是9.0.4)
文档http://www.dbatools.net/doc/bug10204.html 中搜索ORA-21500也发现一行这样的信息:
BUG ID; 5682121
Bug: Multithreaded OCI clients do not mutex properly for LOB operations (ORA-21500 [17099])
我们的代码也的确是在多线程环境下使用PRO*C导致了ORA-21500(P.S PRO*C实际上只是预编译器,仍然需要将PC的代码转换成对OCI的调用,ORACLE应该只用一种API接口,那就是OCI)
因此,到处寻找ORACLE 10G Client for Linux的光盘,找了半天也没找到。没办法,只好自己想办法让这个BUG重现,便于确定是否是自己的代码的问题。
出问题的代码在于自己封装了一个数据库的连接池,其原理是预先分配N个连接,然后每个线程需要连接的时候从连接池中获取一个空闲连接来使用,使用完后立即将连接释放回连接池。这样,每个线程不必一直占用一个连接,也不必每次都直接连接数据库。连接池的代码很简单,看了几遍也没发现哪儿有问题。于是编写了以下的代码来模拟连接池的原理,尝试让ORA-21500重现。
//ORA21500.pc
#ifndef ORA_PROC
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
// 必须先定义这个宏,避免在每个PC文件中生成全局的sqlca变量
#define SQLCA_NONE
#include <sqlca.h>
#endif
#define MAX_CONN 4
#define CONN_STR "webuser/webuser@bsmp"
/**//// 去除PROC函数内的“变量未使用”的警告的宏#define NO_WARNING {sqlstm.sqlvsn = sqlstm.sqlvsn;}
/**//// 分配一个全局的连接池EXEC SQL BEGIN DECLARE SECTION;
sql_context ctx[MAX_CONN];
EXEC SQL END DECLARE SECTION;
/**//// 线程函数void* read_data(void* param)
...{
EXEC SQL BEGIN DECLARE SECTION;
struct sqlca sqlca;
int* index = (int*)param;
int nCount = 0;
int user_id;
EXEC SQL END DECLARE SECTION;
printf("%s %d: index=%d thread=%d ", __FUNCTION__, __LINE__, *index, (int)pthread_self());
EXEC SQL CONTEXT USE :ctx[*index];
EXEC SQL DECLARE CurUser CURSOR FOR
SELECT user_id FROM webuser.user_info WHERE rownum<=100000;
EXEC SQL OPEN CurUser;
do
...{
EXEC SQL FETCH CurUser INTO :user_id;
nCount++;
} while(sqlca.sqlcode==0);
EXEC SQL CLOSE CurUser;
printf("%s %d: user count=%d index=%d thread=%d ", __FUNCTION__, __LINE__,
nCount, *index, (int)pthread_self());
return NULL;
NO_WARNING;
}
/**//// 创建连接池和线程void test()
...{
EXEC SQL BEGIN DECLARE SECTION;
struct sqlca sqlca;
int i;
char ConnStr[100];
int index[MAX_CONN];
EXEC SQL END DECLARE SECTION;
pthread_t threads[MAX_CONN];
strcpy(ConnStr, CONN_STR);
memset(threads, 0, sizeof(threads));
/**//// 创建连接池
for (i=0; i<MAX_CONN; i++)
...{
EXEC SQL CONTEXT ALLOCATE :ctx[i];
EXEC SQL CONTEXT USE :ctx[i];
EXEC SQL CONNECT :ConnStr;
if (sqlca.sqlcode != 0)
...{
printf("%s %d: 连接数据库错误:code=%d, errm=%s ", __FUNCTION__, __LINE__,
sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return;
}
}
//创建线程
for (i=0; i<MAX_CONN; i++)
...{
index[i] = i;
if (0!=pthread_create(threads+i, NULL, read_data, index+i))
...{
printf("%s %d: create thread failed! ", __FUNCTION__, __LINE__);
}
else
...{
printf("%s %d: thread[%d]=%d ", __FUNCTION__, __LINE__, i, (int)threads[i]);
}
}
//连接线程
for (i=0; i<MAX_CONN; i++)
...{
pthread_join(threads[i], NULL);
}
printf("%s %d: end ", __FUNCTION__, __LINE__);
return;
NO_WARNING;
}
int main()
...{
test();
return 1;
}
/**//*
proc userid=webuser/webuser@bsmp parse=partial code=cpp sqlcheck=full threads=yes char_map=string def_sqlcode=false oraca=false objects=false errors=true lines=true auto_connect=no ltype=none hold_cursor=yes release_cursor=no iname=ORA21500.pc oname=ORA21500.cpp cpool=yes cmax=5 cmin=3 cincr=2 ctimeout=2 cnowait=7
g++ -o ORA21500.o -c ORA21500.cpp -g -Wall -Werror -I"${ORACLE_HOME}/precomp/public"
g++ -o ORA21500.exe ORA21500.o "${ORACLE_HOME}/lib/libsql9.a" "${ORACLE_HOME}/lib/libclntsh.so" -lpthread
*/
代码的最后几行是编译命令。编译后执行这个程序,几乎每次都发生core dump, 但是出现ORA-21500信息的次数较少。以上的代码实际上也就是我封装的连接池的原理所在。如此简单的代码也能崩溃掉,看来这真的是ORACLE客户端的BUG无疑了。
正当打算将客户端安装成ORACLE 10g的时候,突然想到修改一下PRO*C的编译参数试试。
于是将proc编译参数中的连接池信息去掉:cpool=yes cmax=5 cmin=3 cincr=2 ctimeout=2 cnowait=7
再编译执行以上代码,结果让我大跌眼睛(还好我不戴眼睛)————居然运行完全正确,没有发生core dump!
恩,从上面的现象看来,ORA-21500内部错误这个BUG与ORACLE的连接池机制有关。关闭连接池暂时可以屏蔽掉这个错误,但是不能肯定在其他环境下不会出现。
OK,综上所述:
1、在PRO*C的编译选项中,如果使用了连接池,多线程下会出现ORA-21500错误;去掉连接池选项即可解决;
2、直接调用OCI代码,在多线程和连接池同时使用的情况下,也可能会出现这个错误;
3、不管怎么样,ORA-21500[17099]始终是一个BUG,最好还是换成ORACLE新版的产品。
分享到:
相关推荐
ora-00604 错误 解决 方法 ora-00604 错误 解决 方法 ora-00604 错误 解决 方法 ora-00604 错误 解决 方法 ora-00604 错误 解决 方法ora-00604 错误 解决 方法
Oracle 11gr2连Oracle 19c 报ORA-28040 ORA-01017解决方法
使用工具IMPDP导入数据时ORA-39002、ORA-39070错误排查。使用工具IMPDP导入数据时ORA-39002、ORA-39070错误排查 使用工具IMPDP导入数据时ORA-39002、ORA-39070错误排查
在oracle里面运行一下,解决Exception java.sql.SQLException ORA-00600 内部错误代码
错误描述:oracle远程连接服务器出现 ORA-12170 TNS:连接超时 错误检查:有很多是oracle自身安装的问题,但是我这里服务器配置正常,监听正常,服务正常,远程可以ping通服务器。 这里主要是防火墙问题,解决办法: ...
Drop goldengate用户时,报ORA-00604 ORA-20782 ORA-06512错误
创建物化视图ORA-12014错误解决方法 创建物化视图ORA-12014错误解决方法
oracle数据库ora-01152和ora-01110的解决办法
ERwin连接oracle报ORA-01041内部错误,hostdef扩展名不存在解决办法,实验可解决问题。
每一个DBA在进行数据库管理的过程中不可避免的要遇到形形色色的错误(ORA- 1547 ,ORA-904,ORA-1578 ......)。有些错误由于频繁出现、原因复杂而被 Oracle DBA 们戏称之为\\\\\\\"经典的错误\\\\\\\"。其中ORA-3113 \\...
离线误删空间文件导致的ORA-01033及ORA-01145问题的解决办法,在解决ORA-01033的过程中,又出现ORA-01145 * 第 1 行出现错误: ORA-01145: 除非启用了介质恢复, 否则不允许立即脱机 接着的解决步骤
oracle启动失败,ORA-00702报错,windows,linux系统下解决办法
oracle的ORA-12514错误 解决办法
关于WIN10系统使用oracle instant client 时候提示ORA-01019错误的解决方案,本方案是配置好环境变量后依然提示ORA-01019错误的解决方案,内附本人制作测试的全过程说明
ORA-12541 TNSno listener 的解决方案 ORA-12541 TNSno listener 的解决方案
用oracle数据库新建连接时遇到ora-12505,此问题解决后又出现ora-12519错误,郁闷的半天,经过一番折腾问题解决,下面小编把我的两种解决方案分享给大家,仅供参考。 解决方案一: 今天工作时在新建连接的时候遇到...
在oracle数据库遇到ora-227101错误的解决办法
ORA-01033ORACLE错误解决
ORA-12560 TNS 协议适配器错误