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

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

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

MFC上基于Access数据库连接实例(ODBC模式)_第1张图片

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

MFC上基于Access数据库连接实例(ODBC模式)_第2张图片MFC上基于Access数据库连接实例(ODBC模式)_第3张图片MFC上基于Access数据库连接实例(ODBC模式)_第4张图片MFC上基于Access数据库连接实例(ODBC模式)_第5张图片MFC上基于Access数据库连接实例(ODBC模式)_第6张图片



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

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关闭以前没有关闭的任何记录集。

下面我们来看具体操作:

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

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

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

#pragma comment(lib,"odbccp32.lib")   //指定连接要使用的库,该库中包含SQLConfigDataSource函数
#include 
//实现类的单例模式
Access* Access::GetInstance() { static Access instance; return &instance;}
 
  

BOOL Access::Connect(LPCTSTR szDbPath)
{
	CString csTemp;
	csTemp.Format(_T("DSN=%s;DBQ=%s"),_T("my_db"),szDbPath);//DSN:新数据源名称;DBQ:数据源地址;

//动态注册数据源
//SQLConfigDataSource()函数可以动态的增加,修改和删除数据源!

	if(SQLConfigDataSource(NULL,ODBC_ADD_DSN,_T("Microsoft Access Driver (*.mdb)"),
	(LPCTSTR)csTemp.GetBuf	fer(256)))
	{
		TRACE("/**********动态注册数据源成功!***********/\n");//调试时TRACE宏信息输出到VC IDE环境			的输出窗口;
	}
	else
	{
		TRACE("/**********创建DSN时出现错误!!***********/\n");
		return FALSE;
	}

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


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

//关闭数据库
void Access::DisConnect()
{
	if(m_pRecordSet != NULL)
	{
		if(m_pRecordSet->IsOpen())
		{
			m_pRecordSet->Close();
		}
		delete(m_pRecordSet);
		m_pRecordSet = NULL;
	}

	if(m_Database.IsOpen())
	{
		m_Database.Close();
	}
}


long Access::Select(LPCTSTR szSQL)
{
	if(m_pRecordSet->IsOpen())
	{
		m_pRecordSet->Close();
	}
       BOOL searchResult = m_pRecordSet->Open(CRecordset::snapshot,szSQL,CRecordset::none);

	if(TRUE == searchResult)
	{
		return m_pRecordSet->GetRecordCount(); 
	}
	else
	{
		return 0;
	}
}


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


CString Access::GetField(const SHORT fieldIndex)
{
	CString csTemp;//要存储字段的值 对象的引用
	m_pRecordSet->GetFieldValue(fieldIndex,csTemp);
	return csTemp;
}

CString Access::GetField(LPCTSTR fieldName )
{
	CString csTemp;
	m_pRecordSet->GetFieldValue(fieldName, csTemp);
	return  csTemp;
}

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

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


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

void CExercise7Dlg::OnBnClickedBtnInsert()     // 插入数据测试
{
	Access *m_access;
	m_access = Access::GetInstance();

	if(TRUE == m_access->Connect(_T(".\\manage.mdb")))
	{
		MessageBox(_T("数据连接成功!"));
	}

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

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

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

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

你可能感兴趣的:(MFC)