MFC上基于Access数据库连接实例(ODBC模式)

下面来写一个简单的小程序,程序实现的功能是能够动态的连接一个在电脑上建好的Access数据表,并能够实现插入、删除、替换数据的功能!

下面来看一下主框架界面:


这个主界面比较简单,就是四个按钮,是用来添加消息响应函数的,主要是实现数据库连接的功能,当按下SELECT测试按钮后,进行数据库连接,并将选定的数据通过对话框显示出来,以示连接成功。当按下INSERT测试按钮后,向Access数据表中插入一行数据,插入成功后显示状态,依次类推,当按下UpdateData测试后,将数据表中的某项数据更新,并显示成功状态,当按下DELETE测试后,将数据表中的某项指定数据删除,并显示成功状态!显示如下:



下面我们先介绍下数据库连接的一些基本知识:

ODBC(Open Datebase Conectivity)即开放式数据库互联,它是微软公司开放服务结构(WOSA,Windows Open Services Architecture)中有关数据库的一个组成部分,它建立了一组规范,并提供了一组对数据库访问的标准API(应用程序编程接口)。这些API利用SQL来完成其大部分任务。ODBC本身也提供了对SQL语言的支持,用户可以直接将SQL语句送给ODBC。


MFC的ODBC类对较复杂的ODBC API进行了封装,提供了简化的调用接口。MFC的ODBC主要包括以下几个类:

  • CDatabase类:主要功能是建立与数据库的连接。
  • CRecordset类:代表从数据源选择的一组记录(记录集)。
  • CRecordView类:提供了一个表单视图与某个记录集直接相连,利用对话框数据交替机制(DDX)在记录集与表单视图的控件之间传输数据。
  • CFieldExchange类:支持记录字段数据交换(RFX),即记录集字段数据成员与相应的数据库的表的字段之间的数据交换。
  • CDBException类:代表ODBC类产生的异常。

数据源是位于一些数据库管理系统(DBMS)的数据的指定实例,包括MicrosoftSQLServer 和MicrosoftAccess和BorlanddBASExBASE为使用CDatabase,构造一个CDatabase对象并调用它的OpenEx成员函数。这打开了一个连接。在接着构造CRecordset对象以操纵连接的数据源时,向CDatabase对象传递记录集构造程序指针。完成使用连接时调用Close成员函数并销毁CDatabase对象。Close关闭以前没有关闭的任何记录集。

下面我们来看具体操作:

首先我们写一个类来包含一系列连接数据库的操作:

<span style="font-family:SimHei;">#ifndef ACCESS_H_H_H
</span><span style="font-family:Times New Roman;">#define ACCESS_H_H_H
#include <afxdb.h></span><span style="font-family:SimHei;">                    //MFC ODBC数据库类的定义文件
</span><span style="font-family:Times New Roman;">class Access</span><span style="font-family:SimHei;">
{
</span><span style="font-family:Times New Roman;">public</span><span style="font-family:SimHei;">:
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>Access(void)</span><span style="font-family:SimHei;">;                        //类的构造函数
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>virtual ~Access(void)</span><span style="font-family:SimHei;">;                 //类的析构函数
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>BOOL Connect(LPCTSTR szDbPath)</span><span style="font-family:SimHei;">;   //实现数据源的动态注册及实现CDatabase类对象与数据源的连接,并                                           将CDatabase类对象的指针传递给CRecordset对象,以便该对象在后                                           面创建记录集
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>void DisConnect()</span><span style="font-family:SimHei;">;                   //断开数据集指针及数据源对象与数据源的链接
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>long Select(LPCTSTR szSQL)</span><span style="font-family:SimHei;">;          //CRecordset类的对象指针调用函数创建记录集,返回的值是指向当前的                                        记录
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>CString GetField(const SHORT fieldIndex)</span><span style="font-family:SimHei;">;  //得到记录集中的字段值,重载函数,形参分别是索引值                                                      和名称
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>CString GetField(LPCTSTR fieldName)</span><span style="font-family:SimHei;">;
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>BOOL Qurey(LPCTSTR szSQL)</span><span style="font-family:SimHei;">;         //执行一条SQL语句
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>static Access* GetInstance()</span><span style="font-family:SimHei;">;             //单例模式,每次只是用一个Access对象
</span><span style="font-family:Times New Roman;">private</span><span style="font-family:SimHei;">:
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>CDatabase m_Database</span><span style="font-family:SimHei;">;                //将CDatabase类的对象作为其成员变量
</span><span style="font-family:Times New Roman;"><span style="white-space:pre">	</span>CRecordset *m_pRecordSet</span><span style="font-family:SimHei;">;            //将CRecordset类的对象指针作为其成员变量
};
#endif</span>

该类的源文件下的几个重要函数代码:

<span style="font-family:Times New Roman;font-size:18px;">#pragma comment(lib,"odbccp32.lib")   //指定连接要使用的库,该库中包含SQLConfigDataSource函数
#include <ODBCINST.h></span>
<span style="font-family:Times New Roman;font-size:18px;"></span><pre name="code" class="cpp"><span style="font-family:Times New Roman;font-size:18px;">//实现类的单例模式</span>
Access* Access::GetInstance() { static Access instance; return &instance;}

 
<span style="font-family:Times New Roman;font-size:18px;">
BOOL Access::Connect(LPCTSTR szDbPath)
{
<span style="white-space:pre">	</span>CString csTemp;
<span style="white-space:pre">	</span>csTemp.Format(_T("DSN=%s;DBQ=%s"),_T("my_db"),szDbPath);//DSN:新数据源名称;DBQ:数据源地址;

//动态注册数据源
//SQLConfigDataSource()函数可以动态的增加,修改和删除数据源!</span>
<span style="font-family:Times New Roman;font-size:18px;">
<span style="white-space:pre">	</span>if(SQLConfigDataSource(NULL,ODBC_ADD_DSN,_T("Microsoft Access Driver (*.mdb)"),</span>
<span style="font-family:Times New Roman;font-size:18px;"><span style="white-space:pre">	</span>(LPCTSTR)csTemp.GetBuf<span style="white-space:pre">	</span>fer(256)))
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>TRACE("/**********动态注册数据源成功!***********/\n");//调试时TRACE宏信息输出到VC IDE环境<span style="white-space:pre">			</span>的输出窗口;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>else
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>TRACE("/**********创建DSN时出现错误!!***********/\n");
<span style="white-space:pre">		</span>return FALSE;
<span style="white-space:pre">	</span>}

//创建对象与数据源的连接
<span style="white-space:pre">	</span>if(m_Database.IsOpen()) //如果CDatabase对象当前与数据源连接,则返回非零
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>m_Database.Close(); //关闭数据源连接
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>BOOL bOpenFlag;
//assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行
<span style="white-space:pre">	</span>ASSERT(TRUE == (bOpenFlag = m_Database.OpenEx(_T("DSN=my_db"),CDatabase::noOdbcDialog)));


//使用CRecordset对象操作数据源时,必须将CDatabase对象的指针传递给他的构造函数,
//并调用成员函数OPEN()创建记录集。
<span style="white-space:pre">	</span>if(m_pRecordSet != NULL)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>if(m_pRecordSet->IsOpen())
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>m_pRecordSet->Close();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>delete(m_pRecordSet);
<span style="white-space:pre">		</span>m_pRecordSet = NULL;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>if(m_pRecordSet == NULL)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>m_pRecordSet = new CRecordset(&m_Database);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return bOpenFlag;
}

//关闭数据库
void Access::DisConnect()
{
<span style="white-space:pre">	</span>if(m_pRecordSet != NULL)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>if(m_pRecordSet->IsOpen())
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>m_pRecordSet->Close();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>delete(m_pRecordSet);
<span style="white-space:pre">		</span>m_pRecordSet = NULL;
<span style="white-space:pre">	</span>}

<span style="white-space:pre">	</span>if(m_Database.IsOpen())
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>m_Database.Close();
<span style="white-space:pre">	</span>}
}


long Access::Select(LPCTSTR szSQL)
{
<span style="white-space:pre">	</span>if(m_pRecordSet->IsOpen())
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>m_pRecordSet->Close();
<span style="white-space:pre">	</span>}
       BOOL searchResult = m_pRecordSet->Open(CRecordset::snapshot,szSQL,CRecordset::none);

<span style="white-space:pre">	</span>if(TRUE == searchResult)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>return m_pRecordSet->GetRecordCount(); 
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>else
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>return 0;
<span style="white-space:pre">	</span>}
}


BOOL Access::Qurey(LPCTSTR szSQL)
{
/**在c++中,可以直接抛出异常之后自己进行捕捉处理,
 *可以在任何自己得到不想要的结果的时候进行中断,
 *比如在进行数据库事务操作的时候,如果某一个语句返回SQL_ERROR则直接抛出异常,
 *在catch块中进行事务回滚)
**/
TRY
{
<span style="white-space:pre">	</span>m_Database.ExecuteSQL(szSQL);           //执行一条SQL语句。不返回数据记录
}
CATCH(CDBException,e)
{
<span style="white-space:pre">	</span>return FALSE;
}
END_CATCH;
return TRUE;
}


CString Access::GetField(const SHORT fieldIndex)
{
<span style="white-space:pre">	</span>CString csTemp;//要存储字段的值 对象的引用
<span style="white-space:pre">	</span>m_pRecordSet->GetFieldValue(fieldIndex,csTemp);
<span style="white-space:pre">	</span>return csTemp;
}

CString Access::GetField(LPCTSTR fieldName )
{
<span style="white-space:pre">	</span>CString csTemp;
<span style="white-space:pre">	</span>m_pRecordSet->GetFieldValue(fieldName, csTemp);
<span style="white-space:pre">	</span>return  csTemp;
}

下面我们再看看在按钮的响应函数中是如何实现对数据的操作的:
void CExercise7Dlg::OnBnClickedBtnSelect()         // 连接测试
{
// TODO: Add your control notification handler code here
<span style="white-space:pre">	</span>Access *m_access;                              //构造ACCESS类的一个对象
<span style="white-space:pre">	</span>m_access = Access::GetInstance();

<span style="white-space:pre">	</span>if(TRUE == m_access->Connect(_T(".\\manage.mdb")))       // 判断是否成功连接数据库
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>MessageBox(_T("数据连接成功!"));
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>int nResult;                    //获取一个给定的字段值,并在消息盒中显示该字段值的第一行数据,意思数据连接成功。
<span style="white-space:pre">	</span>if((nResult = m_access->Select(_T("SELECT * FROM `manageTable`"))) > 0)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>MessageBox(m_access->GetField((short)0).GetBuffer(256));
<span style="white-space:pre">		</span>MessageBox(m_access->GetField(_T("classes")).GetBuffer(256));
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>else
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>MessageBox(_T("数据库查询结果数为0"));
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>m_access->DisConnect();
}

void CExercise7Dlg::OnBnClickedBtnInsert()     // 插入数据测试
{
<span style="white-space:pre">	</span>Access *m_access;
<span style="white-space:pre">	</span>m_access = Access::GetInstance();

<span style="white-space:pre">	</span>if(TRUE == m_access->Connect(_T(".\\manage.mdb")))
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>MessageBox(_T("数据连接成功!"));
<span style="white-space:pre">	</span>}

<span style="white-space:pre">	</span>CString strSQL;               // 此处为SQL语句的标准格式,详情请参考SQL语句。
<span style="white-space:pre">	</span>strSQL.Format(_T("INSERT INTO `manageTable`(`studynum`, `duty`, `name`, `task`, `classes`, `phone`, `qq`, `address`)\
<span style="white-space:pre">	</span>VALUES('%s','%s','%s','%s','%s','%s','%s','%s')"),
<span style="white-space:pre">	</span>TEXT("56"), 
<span style="white-space:pre">	</span>TEXT("组员"), 
<span style="white-space:pre">	</span>TEXT("大头"), 
<span style="white-space:pre">	</span>TEXT("软件"), 
<span style="white-space:pre">	</span>TEXT("机制0805"), 
<span style="white-space:pre">	</span>TEXT("32432324234"), 
<span style="white-space:pre">	</span>TEXT("32423"), 
<span style="white-space:pre">	</span>TEXT("华中科技大学"));
<span style="white-space:pre">	</span>if(TRUE == m_access->Qurey(strSQL.GetBuffer(256)))
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>MessageBox(_T("插入数据成功"));
<span style="white-space:pre">	</span>}
}
</span>

下面的几个按钮的消息响应就类似啦,在此就不啰嗦了。

好了,至此MFC数据库的连接操作就此结束了,现在来做一个总结:

  1. 从这个函数中初窥了ODBC类API的封装及API接口的使用方法,这些方法其实是通用的准则,理解清楚这个,对后续的编程很有好处
  2. 从这个函数中,也进一步理解力C++中类的强大之处,通过ACCESS类对成员函数和成员变量的封装,在主对话框中,我们只需要调用ACCESS类的头文件,并创建一个类的对象,之后就可以利用这个对下对其成员进行调用。
  3. 这个函数中也用到了C++中的一些编程技巧,用好这些方法也是很重要的,如这里有:TRY,CATCH,END_CATCH、TRACE、Format等的使用 。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值