首页 > 代码库 > MFC中使用ADO进行数据库操作

MFC中使用ADO进行数据库操作

参考FROM:http://hi.baidu.com/sunkanghome/item/e1fda510b3186359f1090ee2

数据库与数据库编程:

  • 当前各种主流数据库有很多,包括Oracle, MS SQL Server, Sybase, Informix, MySQL, DB2, Interbase / Firebird, PostgreSQL, SQLite, SAP/DB, TimesTen, MS ACCESS等等。
  • 数据库编程是对数据库的创建、读写等一列的操作。数据库编程分为数据库客户端编程数据库服务器端编程。数据库客户端编程主要使用ODBC API、ADO、ADO.NET、OCI、OTL等方法;数据库服务端编程主要使用OLE DB等方法。
  • 数据库编程需要掌握一些访问数据库技术方法,还需要注意怎么设计高效的数据库、数据库管理与运行的优化、数据库语句的优化。

ADO编程的一般步骤:

  1.   创建一个Connection对象  
  2.   打开数据源,建立同数据源的连接  
  3.   执行一个SQL命令 
  4.   使用结果集
  5.   终止连接

 

ADO最重要的三个对象:

  1. 连接对象(Connection)
  2. 命令对象(Command)
  3. 记录集对象(RecordSet)

在使用这三个对象的时候,需要定义与之相对应的智能指针:_ConnectionPtr、_CommandPtr、_RecordsetPtr

使用智能指针要:定义指针变量、创建其实例(实例化)、调用方法和属性。该智能指针在析构对象时,自动调用Release方法,即使用后不需要手动释放内存,代码更加简洁。

但需要调用Close方法,关闭连接Connection或者记录集RecordSet。

一、ADO编程预处理操作

1.1 导入ADO动态链接库:

在工程的stdafx.h中加入如下语句:

#import "c:\\Program Files\\Common Files\\System\\ADO\\msado15.dll" rename_namespace("ADOCG") rename("EOF","adoEOF") //rename("BOF","adoBOF") no_namespaceusing namespace ADOCG;

注:import代码要在一行中完成,换行需添加‘\‘

 

1.2 初始化OLE/COM库环境:

在基于MFC的应用里,在应用类的InitInstance成员函数中初始化OLE/COM库环境,直接使用AfxOleInit,在退出应用时,该函数自动负责COM资源的释放,比较方便,不用在

ExitInitInstance中添加相关操作:

BOOL CYourApp::InitInstance(){       AfxEnableControlContainer();       //初始化OLE DLLs       if(!AfxOleInit())       {           AfxMessageBox("初始化OLE DLL失败!");           Return FALSE;        }       ......}

 

 

二、ADO进行数据库连接:

2.1 在App类的头文件中定义变量:

_ConnectionPtr m_pConnection;

2.2 创建智能指针的实例:

在App类的cpp文件InitInstance方法中:

m_pConnection.CreateInstance("ADODB.Connection"); //或者m_pConnection.CreateInstance(__uuidof(Connection));

使用‘.‘而不是->创建m_Connection实例,然后m_pConnection->open方法创建连接。

2.3 设置连接字符串,以便指定需要的连接

2.3.1 使用JET数据库引擎实现对Acess2000类型的数据库info.mdb的连接

CString strSQL=_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=info.mdb;User ID=admin;Passward=;");

2.3.2 使用OLE DB提供者实现对SQL Server的标准安全连接串

CString str SQL=_T("Provider=SQLOLEDB;Data Source=local;Initial Catalog=DVDRentDB_Data.MDF;User ID=sa;Password=123456;");

 或者是在此处不设置User ID和Password,而直接在Open的第2、3个参数中设置。

CString strConnection="Provider=SQLOLEDB;DataSource=local;Initial Catalog=DVDRentDB_Data.MDF";m_pConnection->Open((_bstr_t)strSQL,"sa","820415",adModeUnknown);

注意:

  • 上面设置连接字符串的时候,如果过长需要分行时,则每一行都要加上双引号,在最后加上分号即可。
  • 如果是本地服务器,则Data Source=loca l或 本地服务器名(主机名)
  • 若数据库没有设置密码,在连接字符串中可以将其省略,但User ID不能省
  • 若数据库和程序文件不在同一文件夹下,直接写数据库名即可,在InitialCatalog中不需加上该数据库的存储器地址

2.3.3 使用OLE DB提供者实现对远程SQL Server的标准安全连接串

strConnect=_T("Provider=sqloledb;Network Library=DBMSSOCN;"              "Data Source=130.120.110.001,1433;"              "Initial Catalog=MyDateBaseName;"              "User ID=MyUserName;Password=MyPassword;");

2.4 实现对数据库的连接

在ADO的操作中建议使用try...catch( )来捕获错误信息,因为它有时会经常出现一些意想不到的错误

try{     m_pConnection->Open( (_bstr_t) strSQL," "," ",adModeUnknown);}catch(_com_error e)         //捕捉异常{     CString strError;     strError.Format( "连接数据库发生异常! \r \n错误信息:%s",e.ErrorMessage( ) );     AfxMessageBox(errormessage);         //显示错误信息}

 综上:InitInstance方法中可:

if(!AfxOleInit()){      AfxMessageBox("初始化OLE DLL失败!");      Return FALSE;}m_pConnection.CreateInstance("ADODB.Connection"); //或者m_pConnection.CreateInstance(__uuidof(Connection));try   {       m_pConnection->ConnectionTimeout = 3;    //连接ACCESS2000       m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:/Attendence/AttendenceDB.mdb","","",adModeUnknown);   }   catch(_com_error e) {       AfxMessageBox(e.Description() + _T("\n数据库连接失败"));   }   

2.5 关闭数据库连接

一般重载App类的ExitInstace( )函数,调用m_pConnection的Close方法关闭连接即可:

m_pConnection->Close( );m_pConnection=NULL;

注意:由于初始化COM库调用的是AfxOleInit,这种方法初始化COM库的优点就在于资源的释放也是自动进行的,所以不必担心资源泄漏的问题。

 

三、数据库操作:

_CommandPtr接口

      该接口返回一个记录集, 在使用_CommandPtr接口时,可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接串。如果只执行一次或者几次数据库访问操作,后者是比较好的选择。但是,如果频繁访问数据库,并要返回很多记录集,那么应该使用全局_ConnectionPtr接口创建一个数据库连接,然后使用_CommandPtr接口执行存储过程和SQL语句。

_RecordsetPtr接口

       该接口是一个记录集对象, 与前两种对象相比,它对记录集提供了更多的控制功能,如记录锁定、游标控制等。

3.1 使用Recordset对象操作数据库:

假定已经使用连接指针m_pConnection对象创建了数据源的连接:

3.1.1 创建记录集

 _RecordsetPtr    m_pRecordset;                    //声明记录集指针 m_pRecordset.CreateInstance(__uuidof(Recordset)); //创建实例

3.1.2 打开记录集

记录集指针创建完毕后,调用该指针的Open方法打开记录集。

//读取数据库:CString sqlHasRecord;sqlHasRecord.Format("SELECT * FROM WorkUser WHERE MemberID = ‘%s‘" , m_StringNumber);HRESULT hr = m_pRecordset->Open(  
                    sqlHasRecord.GetBuffer(0),
                    _variant_t((IDispatch*)theApp.m_pConnection, true),
                    adOpenDynamic,
                    adLockPessimistic,
                    adCmdText
                   );

Open函数声明如下:

 HRESULT Recordset15::Open ( const _variant_t & Source,         //sql语句、表名、command对象                             const _variant_t & ActiveConnection,   //已经建立好的连接                               enum CursorTypeEnum CursorType,      //用于设置在打开Recordset时提供者应使用的游标类型,默认值adOpenForwardOnly                             enum LockTypeEnum LockType,        //用于设置在打开Recordset时提供者应使用的锁定类型,默认值adLockReadOnly                             long Options ) ;              //获取Source(即Open第一个参数)的方式

如果第一个参数是sql语句则选择adCmdText

如果第一个参数是表名则选择adCmdTable

//读取数据库:CString sqlHasRecord;sqlHasRecord.Format("SELECT * FROM WorkUser WHERE MemberID = ‘%s‘" , m_StringNumber);HRESULT hr = m_pRecordset->Open(sqlHasRecord.GetBuffer(0), _variant_t((IDispatch*)theApp.m_pConnection, true), adOpenDynamic, adLockPessimistic, adCmdText);if (SUCCEEDED(hr)){    while (!m_pRecordset->adoEOF || !m_pRecordset->BOF)//遍历返回的每一条记录    {        CString m_StringID;        m_StringID = (LPCSTR)_bstr_t(m_pRecordset->GetCollect("FeatureID"));//读取id
     m_pRecordset->MoveNext();
}}m_pRecordset->Close();//记录用完之后需要关闭

 

3.1.3 遍历记录集

一般在返回记录集时,通常要遍历结果记录集,以便查看或编辑某一条记录:

注:为了避免发生异常:

MoveFirst、MovePrev之前,需要使用记录集的指针BOF属性来检测当前的记录集指针 是否位于第一条记录之前;

MoveLast、MoveNext之前需要使用记录集指针的EOF属性来检测当前的记录集指针 是否位于最后一条记录之后.

记录集定位

两种定位方法:前者通过设置或者获取AbsolutePosition属性,其值从1开始,并且当前记录为记录集中第一条记录时等于1, 后者通过设置或获取BookMark属性.

 

3.1.4 访问记录集

读取字段值

m_pRecordset->GetCollect (字段名);    // 字符串 -> 字段名 or 整型(long) -> 字段对应的序号

设置字段值

m_pRecordset->PutCollect (字段名,新值);

//两个方法的原型:_variant_t GetCollect ( const _variant_t & Index )void PutCollect ( const _variant_t & Index , const _variant_t &pvar )

 3.1.5 记录集更新(添加、编辑、删除)

 添加新的记录:AddNew

 编辑当前记录:Edit

 删除当前记录:Delete

AddNew方法:直接在表的末尾续加新记录,该方法可以使用参数,在参数中指定要添加的新纪录;

                     也可以不使用参数,而在后面使用PutCollect方法,并需使用Update函数保存新纪录。

 Update方法:用于保存从调用AddNew方法以来所作的任何更改。

//在表的末尾增加新纪录        m_pRecordset->AddNew();//------------------        m_pRecordset->PutCollect("姓名",_variant_t(m_strName));        m_pRecordset->PutCollect("工作单位",_variant_t(m_strComName));        m_pRecordset->PutCollect("单位地址",_variant_t(m_strComAddr));//------------------        m_pRecordset->Update();//更新数据库-将新纪录存入数据库

 

3.1.6 记录集关闭

在对记录集的操作完成后,必须及时关闭记录集。

 if ( m_pRecordset != NULL ) {       m_pRecordset ->Close( );       m_pRecordset =NULL; }

3.2 使用Connection对象操作数据库

1.编辑SQL语句

2.执行connection对象的Excute()方法

//_ConnectionPt m_pConnection 智能指针对象
strSql.Format(_T("UPDATE WorkUser SET MemberName = ‘%s‘, MemberPosition = ‘%s‘ WHERE MemberID = ‘%s‘ "),m_StringName, m_StringPosition, m_StringNumber);try{ m_pConnection->Execute(_bstr_t(strSql), 0, adCmdText);}catch(_com_error e){ MessageBox(e.Description()); return;}

 注:_variant_t和_bstr_t这两个类分别封装并管理VARIANT和BSTR这两种数据类型,VARIANT和BSTR这两种类型是COM中使用的数据类型。

      为了C++中的变量应用到ADO编程中,只能进行数据类型的转换。通过_variant_t和_bstr_t这两个类,就可以方便的把C++类型变量转换成COM中的变量了。
参考:http://baike.baidu.com/view/2798823.htm?fr=aladdin
com编程: http://baike.baidu.com/view/6923408.htm?fr=aladdin

四、实例演示

 4.1 初始化引入相关的库+Connection对象的创建和数据库的连接

#import "c:\\Program Files\\Common Files\\System\\ADO\\msado15.dll" rename_namespace("ADOCG") rename("EOF","adoEOF") //rename("BOF","adoBOF") using namespace ADOCG;
//... ... _ConnectionPtr m_pConnection;
//... ...
if(!AfxOleInit()){ AfxMessageBox("初始化OLE DLL失败!"); Return FALSE;}m_pConnection.CreateInstance("ADODB.Connection"); try { m_pConnection->ConnectionTimeout = 3; //连接ACCESS2000 m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:/Attendence/AttendenceDB.mdb","","",adModeUnknown); } catch(_com_error e) { AfxMessageBox(e.Description() + _T("\n数据库连接失败")); }

 4.2 Recordset对象的声明与创建实例:

_RecordsetPtr m_pRecordset;
m_pRecordset.CreateInstance(__uuidof(Recordset)); //创建实例

 4.3 读取记录内容:

CString sqlHasRecord;sqlHasRecord.Format("SELECT * FROM WorkUser WHERE MemberID = ‘%s‘" , m_StringNumber);HRESULT hr = m_pRecordset->Open(sqlHasRecord.GetBuffer(0), _variant_t((IDispatch*)theApp.m_pConnection, true), adOpenDynamic, adLockPessimistic, adCmdText);if (SUCCEEDED(hr)){    while (!m_pRecordset->adoEOF || !m_pRecordset->BOF)//遍历返回的每一条记录    {        CString m_StringID;        m_StringID = (LPCSTR)_bstr_t(m_pRecordset->GetCollect("FeatureID"));//读取id     m_pRecordset->MoveNext();    }}m_pRecordset->Close();//记录用完之后需要关闭

 4.4 插入新记录:

CString strSql;strSql.Format("INSERT INTO WorkUser(MemberName, MemberID, MemberPosition, FeatureID, BeDeleted, SendedToClient) VALUES(‘%s‘, ‘%s‘, ‘%s‘, %d, 0, 0)",“ZhangSan”,”14S051000”, “Student”, 16);try{        (theApp.m_pConnection)->Execute(_bstr_t(strSql), 0, adCmdText);}catch(_com_error e){        MessageBox(e.Description());        return;}

 4.5 更新记录:

strSql.Format(_T("UPDATE WorkUser SET MemberName = ‘%s‘, MemberPosition = ‘%s‘ WHERE MemberID = ‘%s‘ "),m_StringName, m_StringPosition, m_StringNumber);try{    (theApp.m_pConnection)->Execute(_bstr_t(strSql), 0, adCmdText);}catch(_com_error e){    MessageBox(e.Description());    return;}

 4.6 删除记录:

CString strSql;strSql.Format(_T("DELETE FROM WorkUser WHERE FeatureID = %s "), FeatureID[i]);try{    (theApp.m_pConnection)->Execute(_bstr_t(strSql), 0, adCmdText);}catch(_com_error e){    MessageBox(e.Description());    return FALSE;}

4.7 读取字节流文件:

读取图像数据:

 

 try {     CString sql;     sql.Format("select * from WorkUser where MemberID=‘%s‘",MemberID);     HRESULT hr = m_pRecordset->Open(sql.GetBuffer(0),_variant_t((IDispatch *)theApp.m_pConnection,true),adOpenDynamic,adLockPessimistic,adCmdText);        if(SUCCEEDED(hr))             {            if(m_pRecordset->adoEOF||m_pRecordset->BOF)         {                MessageBox(_T("数据库中没有相应的记录"));                return;         }         else         {                long lDataSize = m_pRecordset->GetFields()->GetItem(imgColName.GetBuffer(0))->ActualSize;                if (lDataSize>0)                {                    _variant_t          varBLOB;                       varBLOB = m_pRecordset->GetFields()->GetItem(imgColName.GetBuffer(0))->GetChunk(lDataSize);                       if(varBLOB.vt == (VT_ARRAY | VT_UI1))                       {                           if(buffer)                              ///重新分配必要的存储空间                           {                                  char *pBuf = NULL;                               SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);                               memcpy(buffer,pBuf,lDataSize);                ///复制数据到缓冲区buffer                               SafeArrayUnaccessData (varBLOB.parray);                           }                       }                   }                else                {                                    MessageBox(_T("数据库中的图像数据为空!"));                    return;                }        }     }    } catch (...) {      MessageBox(_T("数据库访问出错")); } m_pRecordset->Close();

 

 

 

4.8 保存字节流文件:

 

CString sql;    sql.Format("select * from WorkUser where MemberID=‘%s‘",MemberID);    HRESULT hr = m_pRecordset->Open(sql.GetBuffer(0),_variant_t((IDispatch *)theApp.m_pConnection,true),adOpenDynamic,adLockPessimistic,adCmdText);       if(SUCCEEDED(hr))       {           if (!m_pRecordset->adoEOF||!m_pRecordset->BOF)        {            char            *pBuf = buffer;               VARIANT         varBLOB;               SAFEARRAY       *psa;               SAFEARRAYBOUND  rgsabound[1];               if(pBuf)               {                       rgsabound[0].lLbound = 0;                   rgsabound[0].cElements = bufLength;                   psa = SafeArrayCreate(VT_UI1, 1, rgsabound);   //分配的数据类型为unsigned int (1 byte 长度的类型)                for (long i = 0; i < (long)bufLength; i++)                       SafeArrayPutElement (psa, &i, pBuf++);                   varBLOB.vt = VT_ARRAY | VT_UI1;                            varBLOB.parray = psa;                   m_pRecordset->GetFields()->GetItem(imgColName.GetBuffer(0))->AppendChunk(varBLOB);               }               m_pRecordset->Update();           }        else        {            MessageBox(_T("数据库中没有相应用户的记录!"));            return;        }    }       m_pRecordset->Close();

 

 

 

 

 

 

 

  

 

MFC中使用ADO进行数据库操作