1. 例子简介:
a. 这里以一个简单的例子来介绍ODBC数据库应用程序的开发;
b. 使用的DBMS是Access 2003;
c. 在Visual C++ 6.0中编写数据库应用程序;
d. 操作系统是64位Win7;
2. 利用Access 2003创建一个简单的数据库:
a. 打开Access,点击右下角的“新建文件”→点击右侧的“空数据库”;
b. 选择文件路径,注意,Access的数据库文件的后缀为.mdb,这里将文件名取为StudentInfo.mdb,完整路径名为M:\Test Programs\Test\StudentInfo.mdb;
c. 双击“使用设计器创建表”,后者右键→打开也行;
d. 按照如图所示填入信息:
e. 在ID一栏右键→添加主键;
f. 点击工具栏保存按钮,为表取名为BasicInfo;
g. 回到上一个对话框双击打开BasicInfo表,按照如图所示填写表中的内容:
3. 为创建的数据库添加密码:
a. 由于数据库可以同时又多个人访问,因此在修改密码的时候就必须避免在修改时有多个人访问数据库;
b. 因此先关掉刚打开的数据库;
c. 然后在以独占的方式打开刚刚的数据库:菜单栏→打开→选择刚刚建立的数据库文件.mdb→点击打开按钮右侧的下拉按钮→选择以独占方式打开→会弹出对话框提示不安全但是仍然选择打开;
d. 添加密码:菜单栏→工具→安全→添加数据库密码→填写并确认(就是一模一样再输入一次密码以防止用户填错);
e. 至此创建数据库的工作就全部结束了;
4. 为数据库注册数据源:
a. 数据源由操作系统管理(这是理所当然的,因为控制数据源的应用程序也是由操作系统管理的),因此只有将数据库注册给操作系统之后数据库对于应用程序来说才是可见的,数据库在操作系统中注册成为数据源(即应用程序所处理的数据的来源);
b. 首先需要打开ODBC数据源管理器:
i. 在Win7 64为操作系统中,运行里面的odbcad32是32位的,如果用此管理器注册,应用程序无法和其建立联系,必须使用64位的odbcad32;
ii. 64位的odbcad32位于该文件夹中:C:\Windows\SysWoW64\odbcad32.exe
iii. 为了以后方便使用,可以将该可执行文件建立一个桌面的快捷方式;
c. 打开管理器后就可以添加数据源了:
i. 在用户DSN选项卡中点击添加→选择Microsoft Access Driver (*.mdb)→完成;
ii. 输入数据源名称,为STU_INFO;
iii. 点击选择,找到创建的.mdb文件后确定;
iv. 然后就可以在用户数据源中找到创建成功的STU_INFO数据源了;
5. 编写MFC应用程序访问该数据库:
a. 创建一个工程名为StudentInfo的MFC工程;
b. 属性是单文档,并在step 2 of 6中选择数据库视图无文件支持,并选择数据源,ODBC即为STU_INFO,点击确定后需要输入数据库的登陆密码(登录名已经默认为admin了),然后再选择数据库中需要处理的表BasicInfo即可,完成之后直接点击Finish完成Wizard向导创建;
c. 首先创建一个名为“学生信息查询”的对话框,其ID为IDD_STUD_INFO;
d. 然后按照如下图所示添加组件:
其中:
*1. 为对话框添加类,类名为CStudInfoDlg;
*2. 编辑框的ID都以IDC_EDIT_为前缀,ID以及对应添加的成员变量名(以及字符串的最大长度)为(编辑框对应变量的类型都为CString类):
ID m_ID 15
NAME m_name 20
SEX m_sex 10
HOME m_home 20
AGE m_age 10
e. 在CStudInfoDlg类中建立两个特殊的对象:
i. CDatabase m_DB和CRecordset *m_pRecSet;
ii. 前者用于和数据源建立连接,后者用于在查询的记录之间来回偏移以获得记录中的信息;
f. 为五个按钮添加消息响应函数:
void CStudInfoDlg::OnBtnConnectDb()
{
// TODO: Add your control notification handler code here
//新建一个CRecordset类对象
//其参数就是一个数据库对象
//这样就可以使记录指针和数据库建立联系了
m_pRecSet = new CRecordset(&m_DB);//可以不适用delete删除该对象
//因为m_pRecSet->Close()可以销毁该对象
//创建一个ODBC连接字符串
//也可以写成DSN=STU_INFO;UID=admin;PWD=stu
//注意字符串中不能加任何空格,否则会出错
//DSN为数据源的名称,UID即user ID(用户ID),PWD即password(登录密码)
//如果不写后两项则在连接数据源时需要用户手动输入账户和密码
CString strCon = "DSN=STU_INFO";
//OpenEx函数用于连接数据库
//第一个参数用于指明要连接的数据库的信息,即ODBC连接字符串
//第二个参数是DWORD类型的选项,这里不做研究,就填0
//返回类型是BOOL类型,连接成功就是TRUE否则为FALSE
if (!m_DB.OpenEx(strCon, 0))
{
AfxMessageBox("打开数据库失败!");
return ;
}
//Open函数可向数据库传送SQL查询语句
//并将将查询出来的记录形成一张新表,成为记录集
//并让里面的记录指针指向第一条记录
//IsOpen函数可以判断其是否建立了记录集
//在这里就是如果没建立那就用Open函数建立一个
if (!m_pRecSet->IsOpen())
m_pRecSet->Open(CRecordset::dynaset,
_T("SELECT * FROM BasicInfo"));
//Open的第二个参数是一个SQL查询语句字符串
//注意一定要使用_T,因为一般来说数据库都是支持Unicode的
//这里第一个参数用来描述建立数据集的方式,这里是双向滚动的动态集
//该函数检查记录指针是否滚动到了记录末尾
//即最后一条记录的后面一个空记录,就和C语言中的EOF(end of file)一样
//对于一个刚打开并建立起来的记录集,如果一开始就指向EOF就说明该集是空的
if (m_pRecSet->IsEOF())
{
AfxMessageBox("数据库中没有记录!");
return ;
}
m_pRecSet->MoveFirst();//让记录指针指向第一条记录
//需要添加一个成员函数用于将记录中的字段值传给对话框中对应的成员变量
GetRecValue();
UpdateData(FALSE);//将记录信息刷新到对话框中
}
void CStudInfoDlg::OnBtnFirstRec()
{
// TODO: Add your control notification handler code here
m_pRecSet->MoveFirst();
GetRecValue();
UpdateData(FALSE);
}
void CStudInfoDlg::OnBtnNextRec()
{
// TODO: Add your control notification handler code here
m_pRecSet->MoveNext();//指向下一条记录
if (m_pRecSet->IsEOF())
{
AfxMessageBox("这是最后一条记录!");
m_pRecSet->MovePrev();//在指向上一条记录
return ;
}
GetRecValue();
UpdateData(FALSE);
}
void CStudInfoDlg::OnBtnPrevRec()
{
// TODO: Add your control notification handler code here
m_pRecSet->MovePrev();
if (m_pRecSet->IsEOF())
{
//可见第一条记录的前面一条空记录也可以用EOF来检测
//因此IsEOF函数仅仅用来检测记录指针是否无效
//只要超出记录范围都算无效,而并不狭隘地仅仅表示末尾!!!
AfxMessageBox("这已经是第一条记录了!");
m_pRecSet->MoveNext();
return ;
}
GetRecValue();
UpdateData(FALSE);
}
void CStudInfoDlg::OnBtnLastRec()
{
// TODO: Add your control notification handler code here
m_pRecSet->MoveLast();//指向最后一条记录
GetRecValue();
UpdateData(FALSE);
}
void CStudInfoDlg::GetRecValue()
{
//GetFieldValue可以获得当前记录中字段的值并将字段值传给第二个参数
//因此第二个参数必定是引用传参作为输出参数
//第一个参数是记录中字段的编号,是short类型的,并且编号是从0开始的
//编号所代表的字段的顺序就是创建表时所设计(创建的)的属性的顺序
m_pRecSet->GetFieldValue((short)0, m_ID);
m_pRecSet->GetFieldValue((short)1, m_name);
m_pRecSet->GetFieldValue((short)2, m_sex);
m_pRecSet->GetFieldValue((short)3, m_home);
m_pRecSet->GetFieldValue((short)4, m_age);
}
g. 如果用户直接点击退出按钮则会调用系统默认的OnClose函数,但这个函数仅仅就是将对话框销毁,但是不能将建立的记录集以销毁,也不能断开和数据源的连接,因此需要重载这个函数,可以添加CStudInfoDlg类的WM_CLOSE消息响应函数(只有在用户点击了ID为IDCANCEL的按钮后会发送这个消息并调用OnCancel函数),其实现为:
void CStudInfoDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
if (m_DB.IsOpen())//该函数用于判断数据源是否处于连接状态
{
if (m_pRecSet->IsOpen())//如果建立过记录集
m_pRecSet->Close();//就将记录集关闭(即销毁)
m_DB.Close();//由于数据源仍然连接着所以应该关闭
}
CDialog::OnClose();
}
h. 在菜单栏中添加一个名为“学生信息”的选项,在该选项下再添加一个名为“查询”的选项,其ID取为IDM_STUD_INFO_SELECT,并添加一个该选项的CStudentInfoView类的WM_COMMAND消息响应函数(但首先要为View类添加一个名为m_studInfoDlg的对象),其实现为:
void CStudentInfoView::OnStudInfoSelect()
{
// TODO: Add your command handler code here
if (IDCANCEL == m_studInfoDlg.DoModal())
return ;
}