开发环境:VC2005, ADO(msado.dll版本1132 or 1128),线程数量在10~30之间
关键点 : 基于对话框的mfc程序,app的initinstance中调用了AfxOleInit(); 所有的ADO数据库访问被封装在一个dll中;每次查询使用一个新连接,每个查询结果采用临时变量,并立即取出数据后关闭;
问题:
     1. 每次当两个线程同时进行ado操作时必发异常, 比如线程A在 conn->Execute,线程B在RecordSet.CreateInstance; 线程A的Recordset在GetCollect,线程B的RecordSet在CreateInstance时都会异常;
        异常发生的函数基本上在Conn->Execute和RecordSet.CreateInstance这两个函数中;
        后来我对 RecordSet的生成和Conn的查询进行加锁,如下:
        Lock();
        AdoRecordSet rs;
        conn = DBConnPool.GetConnection();
        conn->Execute(strSQL, rs);
        Unlock();
        ...
        use rs;
        rs.Close();        结果use rs;也会和conn的查询以及rs的createinstance冲突导致异常;
        最后,整个加到锁里面, 如下
         Lock();
        AdoRecordSet rs;
        conn = DBConnPool.GetConnection();
        conn->Execute(strSQL, rs);
        ...
        use rs;
        rs.Close();
        Unlock();
        貌似问题可以得到解决;(长时间的运行之后未见异常);        实在是不能理解,明明是不同的连接和结果集,为什么还要同步呢?   2. 在网上查资料,有些人说需要在每个线程的线程函数中调用coinitialize和couninitialize,结果我发现在有的机器上,线程函数的第一句调用coinitialize会返回s_ok,而有的机器上却返回s_false,明明是同样的代码,怎么会有这种区别呢?
请各位不吝赐教,不胜感激.
         
      
    

解决方案 »

  1.   

    1、能解决问题就行。rs.Close也需要同步保护。2、如果线程中已经调用过COM初始化,再次调用将返回S_FALSE,这个没有影响,它还是成功的。
      

  2.   

    使用com组建的线程,都应该进行必要的初始化
    UINT MyProc(LPVOID param)
    {
    HRESULT hr = ::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);     
    if(FAILED(hr))
    {
    AfxMessageBox("初始化 COM 失败!");
    return 1;
    }
    //...
    ::CoUninitialize();
    return 0;}
      

  3.   

    完了...
    我发现我把很多RecordSet传递到Ado之外的业务类进行访问,这下要同步的话困难了~如果这样也要同步的话,估计效率会有很大的损失,因为有些recordset返回的记录很多
      

  4.   

    数据库是MS SQL SERVER2005
    连接的建立是在线程外,在程序初始化的时候建立了50个左右的连接
    以后一直使用这50个连接查询频繁倒是真的,手工操作的话一般不出异常,但是用自动化测试工具(QTP),一般1个小时内会出异常
      

  5.   

    主要有两个可能的异常,一个是
    CreateInstance里面QueryInterface(__uuid(RecordSet), NULL, __uuid(IUnknown), (void*)(pIunknown))函数
    该函数返回s_ok,可pIUnknown却为未初始化的值0xcccccccc,导致后面的执行异常
    另一个是
    Conn->Execute里面的raw_Execute()函数的参数bstr_t的函数operator wchar_t*()异常,追踪发现Execute里面传进去的sql语句是好的,但一到raw_Execute里面的bstr_t,居然是个0x00000000,导致后面的操作失败上面的两个函数都是vc自己内部的函数,我也是在调试中发现的,真是一点办法也没有了
      

  6.   

    IUnknown* pUnk = NULL;
    CreateInstance(__uuid(RecordSet), NULL, __uuid(IUnknown), (void**)&pUnk)_bstr_t变量是怎么构造的?
      

  7.   

    用try{..............
    }
    catch(...){
    }
    捕捉异常吧,弄一个变量看看出现异常的次数是否多到无法忍受
      

  8.   

    try
    {
    }
    catch貌似捕捉不到,程序直接崩溃~~"IUnknown* pUnk = NULL; 
    CreateInstance(__uuid(RecordSet), NULL, __uuid(IUnknown), (void**)&pUnk) 
    _bstr_t变量是怎么构造的?"
    哪个CreateInstance是vc的内部代码,我打字的时候少写了一个*号;
    _bstr_t的构造很简单,就是_bstr_t(_T("select *...")),所有的操作都放在一个队列中?
    有的后续操作要依赖数据库的数据改变的,有的操作要立即返回,貌似有难度~
    问题在于,异常是偶发的,同一段代码运行很多次都不异常,直到某个偶然时机才出现异常
      

  9.   

    可以建立一个connection连接,然后所有的其他线程操作时,公用这一个连接,操作记录集rs,同时各个线程间同步访问connection...