我的意思是程序初始化时建立一个连接(Connection),然后整个程序只要用到数据库的地方都使用它,程序退出时再close掉。这样可行吗?听说会暴吃内存?因为我发现程序里每次查询都连接一次太慢了,用户操作时可以感到明显的延迟(0.5秒左右),所以想避免重复建立连接。我试着做了一个Singleton模式的类(以保证连接对象的全局唯一性),但在最后调用close方法时抛出异常(不知道时什么异常,我用catch(...)抓的)所以我想问:
1。使用这样的长连接会不会有副作用?
2。如何实现?我的系统:WINXP, VC7, MFC

解决方案 »

  1.   

    不用类,你可以直接在应用程序定义一个成员变量
    public:
       _ConnectionPtr m_con;
    然后在BOOL C***App::InitInstance()函数里
    try
    {
    HRESULT hr;
        hr=m_pConnection.CreateInstance("ADODB.Connection");
        if(FAILED(hr))
    {
    AfxMessageBox("连接实例创建失败");
        return FALSE;
    }
    m_pConnection->Open("Driver={SQL Server};Server=192.168.0.12;DATABASE=Wage;UID=;PSW=","","",adModeUnknown);
    //m_pConnection->Open(***********);
    }
    catch(_com_error e)
    {
    CString errormsg;
    errormsg.Format("连接失败,错误:%s",e.ErrorMessage());
    AfxMessageBox(errormsg);
    return FALSE;
    }
    m_pConnection->CursorLocation=adUseClient;
    然后在其他需要使用连接的地方先在顶上用
    extern C***App theApp;
    声明,就可以用theApp.m_con来访问连接了。
      

  2.   

    多谢各位。我刚才试过用全局变量(和全局函数)的方法。但还是一样的问题。下面是我的代码:
    //////////////////////////////////////////////////////////////////////////
    // DBConn.h  片断extern _ConnectionPtr g_pConn;
    extern BOOL g_OpenDBConn();
    extern void g_CloseDBConn();//////////////////////////////////////////////////////////////////////////
    // DBConn.cpp  片断_ConnectionPtr g_pConn;
    BOOL g_OpenDBConn()
    {
    if (NULL == g_pConn) {
    try {
    // 建立数据库连接
    ::CoInitialize(NULL);
    g_pConn.CreateInstance(__uuidof(Connection));
    g_pConn->CursorLocation = adUseClient;
    g_pConn->Open(
    _T("****************"),
    _T(""), _T(""), 0); } catch (_com_error &e) { // 发生错误
    CString sMsg;
    sMsg.Format(_T("建立数据库连接时发生错误:\n\n%s"), e.ErrorMessage());
    AfxMessageBox(sMsg);
    }
    } return TRUE;
    }void g_CloseDBConn()
    {
    if (NULL != g_pConn && (adStateClosed != g_pConn->State)) {
    afxDump << "g_pConn->State = " << g_pConn->State << "\n";
    try {
    g_pConn->Close(); // 关闭连接
    g_pConn = NULL;
    } catch (_com_error &e) { // 发生错误
    afxDump << e.ErrorMessage() << "\n";
    AfxMessageBox(e.ErrorMessage());
    } catch (...) {
    afxDump << "dkjfald"; }

    }
    ::CoUninitialize();
    }////////////////////////////////////////////////////////////////
    // 在需要使用数据库时#include "DBConn.h"... _RecordsetPtr pRecordset;
    try { // 建立数据库连接
    g_OpenDBConn(); // 获取RecordSet数据集
    CString sSQL;
    sSQL.Format(
    _T(" SELECT ****************"), 
    psFilename); _variant_t vSqlOpen(sSQL); pRecordset.CreateInstance(__uuidof(Recordset));
    pRecordset->Open(
    vSqlOpen,
    g_pConn.GetInterfacePtr(),
    adOpenDynamic,
    adLockOptimistic,
    adCmdText); // 逐行读取数据
    while (!pRecordset->adoEOF) { // 略.....

    pRecordset->MoveNext();
    } // 关闭数据集
    pRecordset->Close();
    pRecordset = NULL;

    // g_CloseDBConn();  ///<-- 如果加上这句就OK
    } catch (_com_error &e) { CString sMsg;
    sMsg.Format(_T("发生错误:\n\n%s"), e.ErrorMessage());
    AfxMessageBox(sMsg); }
    ///////////////////////////////////////////////////////////////
    我在C**Doc对象的析构函数里调用了g_CloseDBConn();但调不调用它都是一样的。g_CloseDBConn()函数里不会出错,而是到析构函数返回时才
    抛出异常。最后的代码停在一个叫comip.h的文件中:... private:
        // The Interface.
        //
        Interface* m_pInterface;    // Releases only if the interface is not null.
        // The interface is not set to NULL.
        //
        void _Release() throw()
        {
            if (m_pInterface != NULL) {
                m_pInterface->Release(); ///<-- 停在这里
            }
        }    // AddRefs only if the interface is not NULL
        //
        void _AddRef() throw()
        {
            if (m_pInterface != NULL) {
                m_pInterface->AddRef();
            }
        }...
    ///////////////////////////////////////////////////////////////但如果我每次操作完数据库就调用g_CloseDBConn()关闭连接,则一切OK。我的解决方案中包含不只一个项目,有几个DLL(里面按上述方法使用了数据库),会不会是这个原因呢?
      

  3.   


    pRecordset->Close();
                      pRecordset.Release();
    pRecordset = NULL;
    看看行不行g_pConn也加上g_pConn.Release();
    可以通过View/Debug/Call Stack堆栈窗口看看当前停下的时候在你的代码中是哪一行
    Variables窗口中选择也可以
      

  4.   

    这样消耗的系统资源太多了!
    其实ADO还不是很成熟!
      

  5.   

    我有一个程序就是在程序开始时连接ADO然后在程序退出时关闭,我发现中间只要一用数据库,内存就猛涨,真不知该如何解决
      

  6.   

    我记得在ASP中使用ADO时,官方一些教材不推荐使用楼主所说的固定连接,而推荐用完后关闭close();ADO作为COM会智能维护连接的。速度并没有太大影响。VC中也相通吧?!
      

  7.   

    多谢各位关注。我觉得长连接带来的资源消耗肯定是比较厉害的,也是不可避免的(空间换时间嘛~)。
    而在我的程序里,我有多个DLL,要它们和EXE共享唯一一个连接,无论是用SINGLTON的类,还是用全局变量都有问题。我不知道该怎么做……(知道的大侠请不吝赐教)我现在的做法是:不用全局唯一的连接,但在一些连续的数据库操作中(比如程序启动时读入大量的数据),在多个地方共享一个连接。
    这样既照顾了速度,也避免了占资源的问题。
    然而,在一些涉及用户操作的地方(比如用户点“查询”),还是不得不重新建立连接,糟糕的时候用户会有明显的延迟感。ASP中的ADO连接也和VC里有些不一样吧也许IIS会帮忙管理一个连接池什么的?ADO.NET已经内置了连接池,所以再也没有这个问题了……-----------
    TO: wlzqi(wlzqi)和 jszj:你们的程序是如何实现的?有没有多个DLL?
      

  8.   

    memory_xj(青蛙) 说得不错。上次我们接受微软的专家培训的时候,他也是这样说的,用完了就关闭。用时再打开。
      

  9.   

    我的只有一个exe程序我是在程序启动时,建立一个连接,以后整个程序都使用这个连接,在程序关闭时,自动关闭
    经过一段时间的使用,在操作过程中基本没有什么问题。但在数据库的跟踪器里边,会发现,在程序退出时,数据库服务器要花费很长时间去清除这个连接
    由于我的数据库是通过internet连接的,而且又加了路由什么的,所以,我不想用一次连接一次,那样会很慢的,至少我在程序启动时的连接要花费很长时间
    我在使用程序的时候,由于网络的不稳定,经常出现连接断开的问题,于是我设定了一个定时器,每隔几秒钟来查看连接是否依然,否则就重新连接。但是我就是不知道如何获得连接当前的状态(是否和数据库连接)。我用的是 _ConnectionPtr pConn;
    pConn->GetState()总是返回1,断开时也是返回1