我的意思是程序初始化时建立一个连接(Connection),然后整个程序只要用到数据库的地方都使用它,程序退出时再close掉。这样可行吗?听说会暴吃内存?因为我发现程序里每次查询都连接一次太慢了,用户操作时可以感到明显的延迟(0.5秒左右),所以想避免重复建立连接。我试着做了一个Singleton模式的类(以保证连接对象的全局唯一性),但在最后调用close方法时抛出异常(不知道时什么异常,我用catch(...)抓的)所以我想问:
1。使用这样的长连接会不会有副作用?
2。如何实现?我的系统:WINXP, VC7, MFC
1。使用这样的长连接会不会有副作用?
2。如何实现?我的系统:WINXP, VC7, MFC
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来访问连接了。
//////////////////////////////////////////////////////////////////////////
// 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(里面按上述方法使用了数据库),会不会是这个原因呢?
pRecordset->Close();
pRecordset.Release();
pRecordset = NULL;
看看行不行g_pConn也加上g_pConn.Release();
可以通过View/Debug/Call Stack堆栈窗口看看当前停下的时候在你的代码中是哪一行
Variables窗口中选择也可以
其实ADO还不是很成熟!
而在我的程序里,我有多个DLL,要它们和EXE共享唯一一个连接,无论是用SINGLTON的类,还是用全局变量都有问题。我不知道该怎么做……(知道的大侠请不吝赐教)我现在的做法是:不用全局唯一的连接,但在一些连续的数据库操作中(比如程序启动时读入大量的数据),在多个地方共享一个连接。
这样既照顾了速度,也避免了占资源的问题。
然而,在一些涉及用户操作的地方(比如用户点“查询”),还是不得不重新建立连接,糟糕的时候用户会有明显的延迟感。ASP中的ADO连接也和VC里有些不一样吧也许IIS会帮忙管理一个连接池什么的?ADO.NET已经内置了连接池,所以再也没有这个问题了……-----------
TO: wlzqi(wlzqi)和 jszj:你们的程序是如何实现的?有没有多个DLL?
经过一段时间的使用,在操作过程中基本没有什么问题。但在数据库的跟踪器里边,会发现,在程序退出时,数据库服务器要花费很长时间去清除这个连接
由于我的数据库是通过internet连接的,而且又加了路由什么的,所以,我不想用一次连接一次,那样会很慢的,至少我在程序启动时的连接要花费很长时间
我在使用程序的时候,由于网络的不稳定,经常出现连接断开的问题,于是我设定了一个定时器,每隔几秒钟来查看连接是否依然,否则就重新连接。但是我就是不知道如何获得连接当前的状态(是否和数据库连接)。我用的是 _ConnectionPtr pConn;
pConn->GetState()总是返回1,断开时也是返回1