11.4 练习与实训
图11.11 添加工程的“ADO”引用

图11.12 建立“数据工程”项目
各个窗体界面及项目文件如图11.13—图11.18所示。

图11.13 登录窗体

图11.14口令修改窗体

图11.15 超级用户窗体

图11.16 MDI主窗体

图11.17工程文件

图11.18 工程属性
(2)用户管理程序各窗体事件代码
1)模块代码
为了简化代码设计,一般会在VB应用程序中增加一个代码模块(Module1.bas)用来定义全局变量和通用函数。同时,在工程的启动属性中,启动对象可以是某个窗体,也可以是模块中的一个Main过程。
本项目中添加入一个模块,将程序需要的全局变量、启动过程和数据库访问公共函数编写在内便于所有的窗体调用,节省代码和便于维护。模块代码如下:
Public userID As String //登录用户名
Public userRole As String //登录用户权限
Public conStr As String //数据库连接字符串
PublicmyConn As New ADODB.Connection //数据库连接对象
PublicmySet As New ADODB.Recordset //数据库记录集合对象
Sub main() //主函数,工程从这里启动
conStr=″DSN=mydb″
myConn.ConnectionString=conStr
myConn.Open
frmLogin.Show
End Sub
Sub getRecord(sql As String) //执行查询,返回记录集合
IfmyConn.State=adStateClosed Then
myConn.Open
End If
IfmySet.State=adStateOpen Then
mySet.Close
End If
SetmySet=New ADODB.Recordset
mySet.Open sql,myConn,adOpenStatic,adLockReadOnly,adCmdText n=mySet.RecordCount
End Sub
Sub executeSql(sql As String) //执行SQL代码
IfmyConn.State=adStateClosed Then
myConn.Open
End If
myConn.Execute(sql)
End Sub
Function checkIn(uid As String,pwd As String)As String //登录验证函数
getRecord(″select口令,权限from UserInfo where用户名=′″+uid+″′″)//返回0,1分别代表用户不正确,口令不正确,登录成功则返回用户权限
IfmySet.RecordCount=0 Then
checkIn=″0″
Else
If Trim(mySet(″口令″))=pwd Then
checkIn=Trim(mySet(″权限″))
Else checkIn=″1″
End If
End If
End Function
模块代码中的连接字符串采用了ODBC方式访问,也可以改用以下OleDb方式访问:
conStr=″provider=sqloledb.1;data source=superstar\SQLEXPRESS;initial catalog=school;″
//provider说明访问数据的驱动类型
//data source说明访问数据库服务器的IP或者计算机名(个人版还要加\SQLEXPRESS)//initial catalog说明数据库名
conStr=conStr+″uid=sa;pwd=123″
//uid pwd是登录SQL Server的用户名和口令
或者cnstr=cnstr+″Integrated Security=SSPI;″
//Integrated Security=SSPI;表示采用windows身份验证模式
//可见OLEDB模式将ODBC配置过程中的可视化参数以代码形式设定
2)登录窗体代码
登录窗体是程序管理的入口,主要实现用户身份验证和登录成功后的用户信息保存。登录窗体代码主要包括窗体加载事件、登录按钮单击事件和退出按钮单击事件。
登录窗体主要验证了数据库表数据查询功能,主要代码如下:
Private Sub Form_Load() //窗体加载事件
userID=″″
userRole=″″
End Sub
Private Sub btLogin_Click() //登录按钮单击事件
Dim uid As String,pwd As String,zt As String
uid=Me.txtUID.Text
pwd=Me.txtPWD.Text
zt=checkIn(uid,pwd)
If zt=″0″Then
MsgBox″用户账户信息不正确,请检查输入!″,vbInformation,″登录提示″
Else
If zt=″1″Then
MsgBox″用户口令信息不正确,请检查输入!″,vbInformation,″登录提示″
Else
userID=uid
userRole=zt Me.Hide
MDIForm1.Show
End If
End If
End Sub
Private Sub btExit_Click() //退出按钮单击事件
End //结束整个应用程序
End Sub
3)用户口令修改窗体代码
用户口令修改是提供给每一位成功登录用户的功能,为了防止用户账号口令可能会被其他人恶意修改,口令修改时需要用户输入正确的口令后才能重设新口令。
同时,登录后的用户名已经保存到了全局变量userID中,因此在修改口令时不用输入自己的用户名,程序自动填写用户名,这样也防止了修改其他用户口令的可能。
口令修改窗体代码包括窗体加载、修改口令按钮单击事件和退出按钮单击事件。与登录界面上的退出按钮不同,修改口令窗体是主界面的子窗体,它的关闭不会导致程序的结束,因此窗体的退出按钮事件只涉及卸载自己窗体代码。
用户口令修改窗体主要是验证数据表数据修改功能,主要代码如下:
Private Sub Form_Load() //窗体加载事件
Me.Width=4740
Me.Height=4380
txtUID.Text=userID
End Sub
Private Sub btModify_Click() //修改口令按钮单击事件
Dim pwd As String,pwd1 As String,pwd2 As String
pwd=Me.txtPWD.Text
pwd1=Me.txtPWD1.Text
pwd2=Me.txtPWD2.Text
If pwd1<>pwd2 Then
MsgBox″新口令和确认口令不相同,请检查输入!″,vbInformation,″口令修改″
Else
getRecord(″select倡from UserInfowhere用户名=′″+userID+″′and口令=′″+pwd+″′″)
IfmySet.EOF=True Then
MsgBox″旧口令不正确,请检查输入!″,vbInformation,″口令修改″
Else
executeSql(″update UserInfo set口令=′″+pwd1+″′where用户名=′″+userID+″′″)
MsgBox″口令修改成功!″,vbInformation,″口令修改″
End If
End If
End Sub
Private Sub btExit_Click() //退出按钮单击事件
Unload Me //关闭窗体
End Sub
4)主界面窗体代码
主界面主要应用了菜单进行项目管理,因此窗体代码主要是窗体加载、卸载事件代码和菜单的事件代码。菜单和菜单的每一个子菜单、菜单项都是控件,如果程序会访问的都需要规范化命名。
与MDI子窗体的关闭不同,MDI主窗体的关闭与登录窗体的关闭一样都会导致程序的结束。
Private Sub MDIForm_Load() //窗体的加载代码
myWidth=Me.Width-360
myHeight=Me.Height-1500
superUser.Enabled=False
If userRole=″管理员″Then
superUser.Enabled=True
End If End Sub
Private Sub MDIForm_Unload(Cancel As Integer) //窗体的卸载事件代码
End
End Sub
Private Sub ModifyPWD_Click() //修改口令菜单项单击事件代码
frmModifyUser.Show
End Sub
Private Sub superUser_Click() //超级用户菜单项单击事件代码
frmAdminUser.Show
End Sub
Private Sub ExitSystem_Click() //退出菜单项单击事件代码
End
End Sub
Private Sub about_Click() //关于菜单项单击事件代码
MsgBox″用户账号管理程序1.0!″,vbInformation+vbOKOnly,″系统简介″
End Sub
5)超级用户窗体代码
超级用户对所有的用户账号都具有管理权限,包括了账号的创建、修改和删除功能,也对应了数据库的增删改指令。
账号的创建和其他几个用户账号管理功能不同,其他账号管理功能都是对已经存在的账号操作,属于一定成功行为。账号创建则首先要查询该账号是否已经被注册,只有没有注册的账号才能增加成功,因为用户名是UserInfo表的主键,它是不允许重复的。
而账号的修改和删除操作唯一的要求就是首先要选中一个已经存在的账号,即要有目标对象;同时对账号删除功能来说,只能删除其他的用户账号,不能删除当前登录用户账号。
超级用户窗体主要是由用户列表绑定过程、窗体加载事件和3个操作按钮的单击事件组成,主要代码如下:
Sub bindUser() //手动绑定用户列表
getRecord(″select用户名from UserInfo″)
lstUser.Clear
DoWhile NotmySet.EOF
lstUser.AddItem(Trim(mySet(″用户名″)))
mySet.MoveNext
Loop
End Sub
Private Sub Form_Load() //窗体加载事件
Me.Width=4740
Me.Height=4380
bindUser
End Sub
Private Sub btAdd_Click() //新增用户按钮单击事件
Dim uid As String
uid=Trim(txtUID.Text)
If uid<>″″Then
getRecord(″select倡from UserInfowhere用户名=′″+uid+″′″)
IfmySet.RecordCount>0 Then
MsgBox″该用户已经存在,请更换用户名重新注册!″,vbInformation+
vbOKOnly,″用户注册管理″
Else
executeSql(″insert into UserInfo(用户名,口令,权限)values(′″+uid+′″,′123′,′普通用户′)″)
bindUser
txtUID.Text=″″
MsgBox″用户新增成功,初始口令为123!″,vbInformation+vbOKOnly,″用
户注册管理″
End If
Else
MsgBox″请先输入要新增的用户名!″,vbInformation+vbOKOnly,″用户注册
管理″
End If
End Sub
Private Sub btDelete_Click() //删除用户按钮单击事件
Dim uid As String
If lstUser.ListIndex>=0 Then
uid=lstUser.List(lstUser.ListIndex)
If uid=userID Then
MsgBox″用户不能删除自己的账号!″,vbInformation+vbOKOnly,″用户删除管理″
Else
executeSql(″delete from userInfo where用户名=′″+uid+″′″)
bindUser
MsgBox″用户删除成功!″,vbInformation+vbOKOnly,″用户删除管理″
End If
Else
MsgBox″用户删除失败,请先选中要删除的用户!!″,vbInformation+vbOKOnly,″
用户删除管理″
End If
End Sub
Private Sub btReset_Click() //重置用户口令按钮单击事件
Dim uid As String
If lstUser.ListIndex>=0 Then
uid=lstUser.List(lstUser.ListIndex)
executeSql(″update userInfo set口令=′123′where用户名=′″+uid+″′″)bindUser
MsgBox″该用户口令重置为123!″,vbInformation+vbOKOnly,″用户口令管理″
Else
MsgBox″重置口令失败,请先选中要重置口令的用户!″,vbInformation+
vbOKOnly,″用户口令管理″
End If
End Sub
11.2 相关知识
11.2.1 ODBC接口
早期的程序员在程序中要连接数据库是非常困难的,每种DBMS产生的数据库文件的格式都不一样,程序员要对他们访问的DBMS的底层API有相当程度的了解,通过API来访问特定的DBMS。这就产生了一个问题,当使用的DBMS改变后,或者用户习惯使用的DBMS与开发程序使用的DBMS不符合时,应用软件便无法正常访问DBMS。为了能解决这种问题,能处理各种数据文件的API便产生了,这就是大家都知道的ODBC。
ODBC是通用API的早期产物,它基于结构查询语言(SQL)并以此作为访问数据的标准。其基本思想包括以下两点:
①为用户提供简单、标准、透明的数据库连接的公共编程接口。
②开发厂商根据ODBC的标准去实现底层的驱动程序。

图11.19 传统数据访问方式和ODBC方式的差异
这时大多数DBMS提供了面向ODBC的驱动程序,遵从了这个标准的DBMS被称为ODBC兼容的DBMS。ODBC兼容的数据库包括Access,MS-SQL Server,Oracle,Informix等。
但是仍然存在大量的低级调用,程序员必须将大量的精力放在底层的数据通信中。同时ODBC是针对关系数据库设计的,早先版本并不支持非关系类型数据文件的访问。为了改善这种不友好的接口,使得在程序开发中,数据库访问的工作更加容易,微软公司陆续提出了很多技术标准,其中影响最大的是OLEDB和ADO。
11.2.2 OLEDB和ADO
(1)OLEDB(Object Linking and Embedding,Database)
OLEDB也称为链接和嵌入数据库对象,它是一个基于COM标准的数据存取对象。它能提供对几乎所有常见类型数据文件的操作,如Excel电子表格、有规则或无规则的文本文件、XML文件等。
(2)ADO(ActiveX Data Objects,ActiveX数据对象)
ADO是微软公司提出的应用程序接口(API),用以实现访问关系或非关系数据库中的数据。ADO是基于OLEDB的技术,它将OLEDB的功能封装,对用户透明。同时现在微软公司已经为所有的ODBC数据源提供了一个统一的OLEDB服务提供程序,这就意味着ADO可以通过ODBC或者OLE DB驱动程序访问数据库,这些数据库可以是关系型数据库、文本数据库、层次数据库或者任何支持ODBC或者OLE DB的数据库。
ADO技术是通过ADO对象的属性、方法来完成相应的数据库访问的。ADO主要有以下6种独立对象:
①Connection。连接对象,用来与数据库建立连接。在建立连接前,最主要的是需要设置连接字符串,用来指定连接数据库所用的驱动程序、数据源名称、用户名和密码等。
②Command。命令对象,定义了数据库的一系列操作。使用命令对象来查询数据库,查询结果以数据集对象(Recordset)形式返回。命令对象在操作数据库前需要与一个已经打开的连接对象(Connection)建立关联。
③RecordSet。记录集对象,定义了从数据库返回的一系列记录的集合,该集合可以以3种方式获得:记录集对象的open方法、连接对象的Excecute方法和Command对象的Execute方法。通过数据集可对记录及组成记录的列进行各种操作。
④Error。错误对象,用于描述Connection对象在连接数据库时发生的错误。
⑤Field。域(字段)对象,用来表示RecordSet对象的字段,一个记录行包含一个或多个域(字段)。
⑥Parameter。参数对象,用来描述Command对象的命令参数,是命令所需要的变量部分。
ADO内部对象关系如图11.20所示。

图11.20 ADO内部对象关系
11.2.3 使用ADO访问数据库的步骤
①建立数据库连接对象,并配置其数据库连接字符串属性,明确将以何种方式连接到何种数据库。数据连接对象的建立可以直接建立,也可能是通过连接字符串间接建立。
②通过连接对象或者和连接对象关联了的记录集合对象、命令对象对数据库下达SQL指令。
③关闭数据库连接对象。在数据库访问结束后主动关闭数据库连接对象是一个良好的程序习惯,既可以节省系统资源,也可以避免一些误操作错误。
ADO重要对象的属性和方法见表11.1—表11.6。
表11.1 Connection对象的常用属性

表11.2 Connection对象的常用方法

表11.3 Command对象的常用属性

表11.4 Command对象的常用方法

表11.5 Recordset对象的常用属性

表11.6 Recordset对象的常用方法

11.3 任务小结
在本任务中主要介绍了如何定义用户ODBC,以及在Visual Basic程序中ADO如何利用ODBC和OLEDB进行数据库连接、数据库数据的查询、增加、删除和修改操作。熟练掌握这些知识并能灵活应用,则绝大多数程序设计中的数据库访问操作都可以胜任了。当然局限于知识目标,并没有对Visual Basic程序设计语言的高级数据库控件进行介绍,读者如果需要这些知识可继续学习Visual Basic的知识来掌握。
11.4 练习与实训
(1)问答题
①ODBC的含义是什么?它的作用是什么?
②ADO的作用是什么?
(2)实训题
在实训任务1基础上,增加学生检索功能。对Student数据库中的学生表进行组合查询,包括使用姓名、学号两个字段的单个或组合,要求支持模糊查询。