牵着老婆满街逛

严以律己,宽以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

OTL建立连接时可能会遇到的一个bug

来源:http://blog.superliufa.com/?q=node/352

  最近因为工作原因,从OCICPP改为用OTL做Oracle开发。初时挺诧异的,怎么只有.h没有.cpp?看过才知道原来一个头文件就全做完了。它是对OCI的一个封装,可以用stream的方式去操作数据库。用起来还是比较简便,但是感觉封装得多了点。虽然OCI那些函数也挺复杂的,但至少觉得一切都在自己掌握之中。OTL这么一封装了之后,有一些实现细节就不得而知了,这就导致了今天发现的一个bug。

  根据OTL关于otl_connect的说明,其构造函数之一是可以直接用来连接数据库的。虽然正儿八经做这个事情的是rlogon(db_string),但是对构造函数otl_connect(connect_str, ...)的说明是其等于otl_connect(void)再加上一个rlogon(connect_str)。所以,一般就这样写了:otl_connect* pdb = new otl_connect("..."); 然后把pdb存在自己的数据库连接池中。如果连接失败,那么会抛出一个otl_exception异常。
  可是,今天却遇到意外。连接字符串中,tnsname写对了,但用户名/密码没对。于是测试的时候发现,多次连接之后,数据库那边内存爆掉了,ORACLE.EXE的线程数也多到疯掉。别的客户端全连接不上了,报ORA-00020错误。
  process数满,这倒也在情理之中。可是看了看session,发现会话其实很少。猜测是什么东西没有释放掉,不是connect就是cursor。查了一下代码,发现没有什么大问题,connect都是连接池管理,不会无限多下去的。otl_stream也都是在栈中声明,花括号之后就自动析构了,cursor也不应该是问题。郁闷中,发现正常的连接反而不会有泄漏发生,会泄漏的都是连接错误的时候。但是连tnsname都不对反而就不会了,估计是因为OCI那边根本就无法建立一个连接,也就耗不了资源。这下定位到了,就是这个创建连接的代码上有问题。

  这段创建连接的代码是这样写的。注意其中捕捉异常的部分:

try
{
  otl_connect
* pdb = NULL;
  pdb 
= new otl_connect("");
}

catch(otl_exception& e)
{
  ……
  
if (NULL != pdb)
    delete pdb;
  pdb 
= NULL;
}

  可以看到,如果连接不成功时没有生成对象,那么应该返回空指针,这样delete指令也不会发生。如果有对象生成,那么在异常处理代码中应该已经把这个对象给销毁了,而对象占用的资源应该也已经释放了。但事实就是不同,由于OTL在这个构造函数中封装了实现细节,而显然这个实现并不完美,于是有了泄漏。

  采用如下的代码,便不存在这个问题了:

try
{
  otl_connect
* pdb = NULL;
  pdb 
= new otl_connect();
  pdb
->rlogon("");
}

catch(otl_exception& e)
{
  ……
  
if (NULL != pdb)
    delete pdb;
  pdb 
= NULL;
}

  根据OTL的说明,这两种建立连接的方法应该没有区别。不过现在才有点明白为什么OTL提供的范例代码都采用后一种方法了。

  追进OTL的头文件中去看,应该可以弄明白原委。不过为了完成任务,没有那么多时间了,这个任务只好留到下次再说。大致估计了一下,应该是因为在new otl_connect(connect_str)的时候就抛了异常,于是代码跳转到了catch处,pdb根本没得到对象指针的赋值,这样新生成的对象就丢了。建议用OTL的各位,在栈中是无所谓啦,但如果要在堆中初始化一个连接,千万不要图省事想用构造函数直接一步到位哦!

posted on 2008-06-13 00:09 杨粼波 阅读(2174) 评论(2)  编辑 收藏 引用

评论

# re: OTL建立连接时可能会遇到的一个bug [未登录] 2008-06-13 17:24 starofrainnight

代碼有問題!

try
{
  otl_connect* pdb = NULL; // 此 pdb 變量在大括號範圍外不存在!
  pdb = new otl_connect("");
}
catch(.....)
{
..... // 這裡對pdb進行操作,哪裡來的 pdb 變量?
}

代碼應該改為:

otl_connect* pdb = NULL;
try
{
  pdb = new otl_connect("");
}
catch(.....)
{
..... // 這裡對pdb進行操作
}

否則,根本不能通過語法校驗!或者博主用的是一個特殊版本的C++編譯器?
  回复  更多评论   

# re: OTL建立连接时可能会遇到的一个bug 2008-06-18 10:22 superliufa

笔误,写博的时候随手写的代码上去。一开始并没考虑写try/catch括起来。多谢指出!  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理