有关数据库的开发做的很少,以前都只是算法类的程序编写,现在对在VC++中连接sqlserver数据库的方法做个总结,以备以后查阅
首先,在stdafx.h头文件中添加以下语句
#import "C:\ProgramFiles\CommonFiles\System\ado\msado15.dll"no_namespacerename("EOF","adoEOF")
导入ado库,no_namespace表示无命名空间,rename("EOF","adoEOF")表示重命名eof 为 adoefo 避免和其他的常量冲突
接着,在MFC中可以用AfxOleInit();非MFC环境中用:
CoInitialize(NULL);
CoUnInitialize();
一般MFC程序中都是默认初始化Com口的。
然后,创建ADO连接数据库的智能指针,下面将分别讲述如何利用_ConnectionPtr和_CommandPtr以及_RecordsetPtr连接数据库的方法
1.利用_ConnectionPtr连接和操作数据库
_ConnectionPtr pConnectionPtr;
//连接字串,连接Sqlserver
CString strConnection = "Provider=SQLOLEDB;Persist Security Info=False;Integrated Security=SSPI;Initial Catalog=ImageDB;Data Source=.\\SQLEXPRESS";
pConnectionPtr.CreateInstance("ADODB.Connection");
HRESULT hr=pConnectionPtr->Open(_bstr_t(strConnection),"","",adConnectUnspecified);
if (FAILED(hr))
{
pConnectionPtr.Release();
return;
}
CString strSql = "insert into StudentInfo values('wang',22,'boy')";
COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR);
pConnectionPtr->Execute(_bstr_t(strSql),vtOptional,-1);
pConnectionPtr->Close();
pConnectionPtr.Release();
_ConnectionPtr返回一个记录集或空指针,通常使用它来创建数据库连接和执行一条不返回任何结果的SQL语句,如一个存储过程。使用_ConnectionPtr返回一个记录集不是一个好的使用方法,对于要返回记录的操作,通常用_RecordsetPtr来实现,使用_ConnectionPtr来操作时想要得到记录的条数得遍历所有的记录,而用_RecordsetPtr时不需要
2.利用_CommandPtr来连接和操作数据库
_CommandPtr pCommandPtr;
pCommandPtr.CreateInstance("ADODB.Command");
pCommandPtr->ActiveConnection = pConnectionPtr;
pCommandPtr->CommandText = "insert into StudentInfo values('wang',22,'boy')";
pCommandPtr->Execute(NULL,NULL,adCmdText);
pCommandPtr->CommandText = "select * from StudentInfo";
_RecordsetPtr pRecordsetPtr = pCommandPtr->Execute(NULL,NULL,adCmdText);
_variant_t vName = pRecordsetPtr->GetCollect((_variant_t)(long)0);//取得第一个字段
CString sName = (LPCTSTR)_bstr_t(vName);
pCommandPtr.Release();
pRecordsetPtr->Close();
_CommandPtr返回一个记录集。
它提供了一种简单的方法来执行返回记录集的存储过程和SQL语句。
在使用_CommandPtr接口时,你可以使用全局的_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接字串。
如果你执行一次或几次数据库操作,使用连接字串是比较好的选择。
如果你要频繁访问数据库,并返回很多记录集,那么使用全局的_ConnectionPtr是个比较好的选择。
3.利用_RecordsetPtr连接和操作数据库
_RecordsetPtr pRecordsetPtr;
pRecordsetPtr.CreateInstance("ADODB.Recordset");
CString strConnection = "Provider=SQLOLEDB;Persist Security Info=False;Integrated Security=SSPI;Initial Catalog=ImageDB;Data Source=.\\SQLEXPRESS";
CString strSQL = "select name,age,sex from StudentInfo";
if (FAILED(pRecordsetPtr->Open(_variant_t(strSQL),_variant_t(strConnection),adOpenStatic,adLockOptimistic,adCmdText)))
{
pRecordsetPtr->Close();
return FALSE;
}
while(!pRecordsetPtr->GetadoEOF())
{
_variant_t VarName;
_variant_t VarAge;
_variant_t VarSex;
VarName = pRecordsetPtr->GetCollect("Name");
VarAge = pRecordsetPtr->GetCollect("Age");
VarSex = pRecordsetPtr->GetCollect("Sex");
CString sName = (char *)_bstr_t(VarName);
CString sAge = (char *)_bstr_t(VarAge);
CString sSex = (char *)_bstr_t(VarSex);
pRecordsetPtr->MoveNext();
}
pRecordsetPtr->Close();
pRecordsetPtr.Release();
与以上两种对象相比,它对记录集提供了更多的控制功能,如记录锁定,游标控制等。
同_CommandPtr接口一样,它不一定要使用一个已经创建的数据连接,
可以用一个连接串代替连接指针赋给_RecordsetPtr的connection成员变量,
让它自己创建数据连接。
如果你要使用多个记录集,
最好的方法是同Command对象一样使用已经创建了数据连接的全局_ConnectionPtr接口,
然后使用_RecordsetPtr执行存储过程和SQL语句。
下面给出一个完整点的例子,作用是保存本地的bmp图片到数据库中
CFile file;
int iLen;
if( !file.Open( "Test.bmp", CFile::modeRead) )
return ;
iLen = (DWORD)file.GetLength();
char* pBMPContent = new char[iLen + 1];
if(!pBMPContent)
return ;
if(file.Read(pBMPContent,iLen) != iLen)
return ;
//保存到数据库
_ConnectionPtr pConnectionPtr;
_RecordsetPtr pRecordsetPtr;
_CommandPtr pCommandPtr;
try
{
CString strConnection = "Provider=SQLOLEDB;Persist Security Info=False;Integrated Security=SSPI;Initial Catalog=ImageDB;Data Source=.\\SQLEXPRESS";
pConnectionPtr.CreateInstance("ADODB.Connection");
pConnectionPtr->Open(_bstr_t(strConnection),"","",adConnectUnspecified);
pRecordsetPtr.CreateInstance(__uuidof(Recordset));
//+--------------------------------------------------------------+
//+ 利用Command执行SQL语句,判断当前项目是否已存在图,若存在则删除
//+ 在项目中修改图时会出现这种情况
char *lpszRetValue = (char *)malloc(sizeof(char)*255);
pCommandPtr.CreateInstance(__uuidof(Command));
pCommandPtr->CommandTimeout = 30;
pCommandPtr->ActiveConnection = pConnectionPtr;
sprintf_s(lpszRetValue,254,"select Count(*) RstCount from ImageTable where ProjectName = '%s' and ExperimentName = '%s'",m_sProjectName,m_sExperimentName);
pCommandPtr->CommandText = lpszRetValue;
pRecordsetPtr = pCommandPtr->Execute(NULL,NULL,adCmdText);
_variant_t vtValue;
vtValue = pRecordsetPtr->GetCollect("RstCount");
if (NULL != vtValue.vt)
{
strncpy((char*)lpszRetValue,LPCSTR(_bstr_t(vtValue)),255);
}
int iRstCount = atoi(lpszRetValue);
free(lpszRetValue);
if (iRstCount != 0)
{
sprintf_s(lpszRetValue,254,"delete from ImageTable where ProjectName = '%s' and ExperimentName = '%s'",m_sProjectName,m_sExperimentName);
pCommandPtr->CommandText = lpszRetValue;
pCommandPtr->Execute(NULL,NULL,adCmdText);
}
pRecordsetPtr->Close();
//+--------------------------------------------------------------+
HRESULT hr = pRecordsetPtr->Open("select * from ImageTable",_variant_t(pConnectionPtr,true),adOpenDynamic,adLockPessimistic,adCmdText);
pRecordsetPtr->AddNew();
SYSTEMTIME st;
CString sSaveTime;
GetLocalTime(&st);
sSaveTime.Format("%4d-%02d-%02d %02d:%02d:%02d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);
pRecordsetPtr->PutCollect("SaveTime",_variant_t(sSaveTime));
pRecordsetPtr->PutCollect("ProjectName",_variant_t(m_sProjectName));
pRecordsetPtr->PutCollect("ExperimentName",_variant_t(m_sExperimentName));
VARIANT varBLOB;
SAFEARRAY *psa;
SAFEARRAYBOUND rgsabound[1];
rgsabound->lLbound = 0;
rgsabound->cElements = iLen;
psa = SafeArrayCreate(VT_UI1,1,rgsabound);
for (long i=0;i<(long)iLen;i++)
{
SafeArrayPutElement (psa, &i, pBMPContent++);
}
varBLOB.vt = VT_ARRAY | VT_UI1;
varBLOB.parray = psa;
pRecordsetPtr->GetFields()->GetItem("Information")->AppendChunk(varBLOB);
pRecordsetPtr->Update();
}
catch (_com_error e)
{
dump_com_error(e);
}
if (pConnectionPtr->State)
{
pConnectionPtr->Close();
pConnectionPtr.Release();
}
if (pRecordsetPtr->State)
{
pRecordsetPtr->Close();
pRecordsetPtr = NULL;
}