自SQL Server出现以来,人们已经开发出各种形式的软件,但是这些软件的核心都是服务器执行的查询,执行的查询都以SQL语言为基础,一般从查询Query Analyzer实用程序输入或执行。但是,当使用SQL Server系统开发一个应用软件时,这种方法表明并不十分有用。负责信息格式化、演示及其他与用户交互的客户机程序才是SQL Server对一般用户的魅力所在。应用软件与SQL Server相接的方式与幕后定义表格、建立存储步骤和优化系统使之充分发挥潜力等工作一样重要。
本章中,我们将从应用软件开发的角度介绍几种与SQL Server配合使用的方法。
值得注意的是,目前开发的软件一般使用高级数据对象(ADO)。这种方法适用于活动服务器网页的开发(Web开发),也适用于Visual Basic和C语言的实现。有关此方法的详情,将在下一章“用OLE DB和ADO开发数据库应用程序”中介绍。
每种技术都是与SQL Server配合使用的综合环境,本章的目的是简要介绍如何选择适当、有效的开发方法。与SQL Server配合使用最常用的方法是:
n DB-Library
n ODBC和数据访问对象(DAO)
n SQL OLE
下面几节将回顾每个基本选项,并解释在SQL Server中的用途。
DB-Library即DB-LIB,是C和Visual Basic(VB)语言环境的API,它可直接与SQL Server配合使用。API提供的各种工具有助于从SQL Serve发送查询和接收信息。它还允许从查询返回的结果集中提取信息,由这种方法处理信息。
@ Microsoft表示将不再改进DB-LIB技术。这里介绍它的原因是许多遗留系统仍在使用此技术。如果正在开发新应用软件,应通过OLE-DB与服务器程序相连。
要使用DB-LIB,应包括一些其他补充文件。VB和C语言环境所需的文件如表20-1所示。
表20-1 DB-LIB所需的组件
|
C |
Visual Basic |
|
SQLCB.H |
VBSQL.OCX |
|
SQLFONT.H |
VBSQL.BAS |
表20-2所示是通过Borland的开发工具(包括C++)开发应用软件时会用到的各种组件。注意要使用于应用软件环境匹配的内存模式。
表20-2 Borland DB-LIB所需的组件
|
组件文件 |
说 明 |
|
BLDBLIB.LIB |
大内存模式静态库 |
|
BMCBLIB.LIB |
中内存模式静态库 |
用Microsoft环境开发时所使用的组件稍有不同,如表20-3所列。
表20-3 面向Microsoft的组件(C++等)
|
元 素 |
说 明 |
|
MSDBLIB3.LIB |
Windows:输入库 |
|
NTWDBLIB.LIB |
Win32:输入库 |
|
RLDLIB.LIB |
DOS:大内存模式静态库 |
|
RMDBLIB.LIB |
DOS:中内存模式静态库 |
使用DB-LIB一般遵循特定的调用周期,包括注册、对服务器执行一种或多种操作,然后从SQL Server退出。
与服务器建立连接通常使用两种结构。dbproc和login都可用于建立和继续应用软件与SQL Server间的通信。
首先使用DBPpen API调用建立与服务器的连接。DBOpen将建立DBProcess结构,提供通过此服务器连接继续工作所需要的信息。在VB和C语言中实现这些步骤的各种方法如表20-4所示。
表20-4 SQL Server与DB-LIB实现通信的基本组件
|
说 明 |
Visual Basic |
C |
|
建立新的注册结构 |
SqlLogin% |
dblogin |
|
为注册设置用户名 |
SqlSetLUser |
DBSTLUSER |
|
为注册设置密码 |
SqlSetLPwd |
DBSTLPWD |
|
设置客户机应用软件名 |
SqlSetLApp |
DBSTLAPP |
|
打开与SQL Server的连接 |
SqlOpen% |
dbopen |
|
关闭与SQL Server的连接 |
SqlClose |
dbclose |
|
关闭所有连接 |
SqlExit |
dbexit |
这些语句可用于创建新的注册结构并填充所需区域。注册结构还有其他属性,但只需用户名和密码。
如果使用集成安全特性,就需要这些字段,但建立连接时服务器忽略它们。服务器将使用来自当前注册用户的用户机密信息。用户如果事先知道使用的是集成安全特性,可以越过这些字段中的任意信息。例如,“blah”用户名密码就已足够。由于用户将接收其网络注册的身份认证,因此不再需要用户ID和密码。注册时将为用户提供另一个对话框。
@ 描述性名称并不是非有不可,但最好使用。因为如果由系统管理员使用SQL Server并管理开放式连接时,所提供的名称就会显示在连接清单中。如果提供了所需信息,管理员就能随时了解服务器使用人的情况。因此,应该避免在应用软件上登入所有用户作为应用软件名。如果能提供应用软件名和站点ID或用户ID,应添加某些键确定管理员可以使用的元素。使用注册结构和服务器名建立打开连接的调用并打开服务器连接。键入open命令时,调用建立结构返回。以后调用服务器时,无论何时向服务器发出命令,都使用此结构指针。
使用注册结构及服务器名称时,打开连接的请求被响应并打开与服务器的连接,发出Open命令时,结构建立并由调用过程返回,在以后的调用中,可以使用此结构指针。
SQL Server注册和注销操作按性能术语来说属代价最高的事务之一。每次注册都需请求或一系列的请求而后注销,将会发现应用程序的运行速度比预料的慢。
为解决这个问题,可以为每类工作使用独立连接。例如,如果在前台有一销售系统,可采用一个系统维持与库存表及会计收账与现金支出表的开放连接,这样能提高性能。
这样,在加载应用软件过程中就能有充裕的时间建立与SQL Server的连接。由于连接已存在,访问独立表的时间将会减少,用户就能更快地进入事务处理。这时需考虑的一个问题是与SQL Server的许可连接数,即必须保证执行的许可证不多于为SQL Server购买的许可证数。如果使用了超额许可证,应重新考虑应用软件,另行购买许可证或结合使用两种方法以提高性能/价格比。
向SQL Server发送语句时,首先在SQL命令缓冲区中建立语句。将命令送入缓冲区的工作通过用所需的参数调用SqlCmd实现。
@ 这里举的例子大部分都与VB有关。虽然C中的实际语句有所不同,但调用规则相似,许多方法也基本相同。
VB中的SqlCmd()句法如下:
status%=SqlCmd(MyConnection%,"<statement>")
每个语句都将添加到当前SqlCmd结构中已有的语句中。如果需要多行语句,应特别注意。用户定义的字串和缓冲区原有的信息是简单的串连关系,例如:
…
statu%=AqlCmd(Myconnection%,"select*from pubs")
statu%=AqlCmd(Myconnection%,"where author like'A%'")
…
为什么此语句会显示语法错误和失败呢?原因是上例中“pubs”和“where”间没有空格,这时就会产生语法错误。
创建缓冲语句后,应将其送至SQL Server以待执行。使用的语句是SqlExec。
Status%=SqlExec(MyConnection%)
由于已经将命令排序并与特定连接建立联系,SqlExec准确知道执行的内容。它将缓冲语句送至SQL Server,并允许SQL Server转换和执行请求。在此例中,送给SQL Server的整个语句为SELECT*from pubs where author like 'A%'(如前所示加上空格)。
如果想调用存储步骤,可以先创建命令然后在前面加上Execute,例如:
…
status%=SqlCmd(MyConnection%,"Execute GetAuthors'A%'")
…
这样可以执行存储步骤GetAuthors并将参数‘A%’传送到存储步骤,假定被用作搜索值。执行调用和处理返回结果原理相同,都假设已发出select语句。
将请求送至SQL Server后,还应能处理从请求返回的信息。这时需要使用两个常数监视所用的数据集。这些常数在.BAS文件中定义,要求文件用DB-LIB库开发。这两个常数是:
n SUCCEED
n NOMOREROWS
处理自SQL Server返回的结果的方法是,沿返回行自上而下直到接收到NOMOREROWS为止,此符号表示应用软件已将所有返回行全部处理完毕。使用SqlResults%函数可以获取记录的当前状态。此函数返回SUCCEED或NOMOREROWS,应用软件可根据这些信息决定下一步行动。
starus%=SqlResrlts%(MyConnection%)
进入处理循环之前应先调用SqlResrlts,这样可以保证处理的不是空数据集。如果已成功地从查询返回信息,可以使用SqlNextRow%浏览结构。SqlNexRow将逐行扫过结果。结果存放在工作缓冲区中以便使用。当SqlNexRow到达数据集的底端时,它将返回NOMOREROWS以便让应用软件停止处理数据集。
@ DB-LIB函数返回的结果是计算属性而非名称属性。处理返回的列时,应使用数字而不是名称标示列。因此,必须记住select语句或存储步骤中所列的定义顺序,否则,请求的信息列可能无法返回期望值,而返回其他列的信息。
处理信息的最后一步是从缓冲区取回信息,所用的函数一般是SqlDatLen。下列程序是一个简单的处理循环,作用是打印作者名称。
…
status%=SqlCmd(MyConnection%,"select au_lname fron authers")
status%=AqlExec(MyConnection%)
While SqlNextRow%(MyConnect%)<>NOMOREROWS
Print SqlData%(MyConnection%,1)
Wend
Print"No more information to present."
…
处理完某个连接后,必须及时关闭,以释放与之相关的内存并断开与服务器的连接。SqlClose函数便可关闭相关连接。
Starus%=SqlClose%(MyConnection%)
用户必须关闭访问服务器时打开的每个连接。当然,也可以调用SqlExit,它将关闭与服务器的所有当前连接。如果应用软件已结束并正在退出,那么使用SqlExit语句既容易又能确保关闭所有连接。
除借助客户机应用程序分布OCX外,客户机应用软件不再要求其他外部模块(当然仍需提供编写的编码模块)。DB-LIB添加的功能在OCX和BAS文件中提供。
在C环境中,应用软件和网络环境中必须包括相应的DLL(Dynamic Linking Library,动态链接库)。如前所述,DLL将随采用的LIB不同而不同。详情请参见表20-2和表20-3。
DB-LIB是SQL Server的专用接口层。这意味着与SQL Server配合使用的三种方法中,这种方法在后台数据库服务器间的“便携性”最差,但访问信息的速度最快。原因是它不只是优秀的接口,而且可以直接用宿主语言开发。其他方法(ODBC和SQL OLE)提供的服务相似,但在应用软件与SQL Server调用间加入了抽象层。
DB-LIB的手工操作很多,原因是创建并发出了Select和Update等语句,但没有自动更新的值。这有助于控制与服务器的接口,优化连接并保证所有数据符合条件。另外,还可能通过与事物处理相关的错误捕获实现全面控制。
DB-LIB是与SQL Server的API级接口,注意不能用这种方法借助Access和Excel等面向用户的工具使用SQL Server。这些工具使用抽象层(开放数据库连接(ODBC)或OLE-DB)与开发人员依赖性不强的数据库协作。
如果你在个计算机产业工作过若干年,就应该了解安装和使用的数据库应用软件种类繁多。这种情况在开发应用软件时尤为突出,如开发数据库查询程序时,需涉及许多人设计的多种数据库。
ODBC试图改变这种状况,但需付出一定的代价。解决方案的好坏将取决于多种因素,包括计划采用某解决方案的站点有多少种数据库等。
推出Visual Basic 4的同时,Microsoft还推出了新的SQL数据管理对象(SQL-DMO)。这样可更容易地使用与数据库相关的各种对象,如数据库、表和规则等。
SQL-DMO使用Visual Basic中的对象创建而成。即使不熟悉对象,也应了解创建新对象、使用一般属性和使用集合等概念。
用户还应学会怎样引用从Visual Basic中设置到SQL对象点上。设置对象类型应使用以下语句:
Dim objSQLServer as New SQLDMO.SQLServer
建立完以后,就可以使用与SQL Server相关的各种对象,即像引用其他属性、方法和与其他对象相关的连接那样随意引用它们。例如,假设在某个数据库中使用表格,可引用如下:
Dim objSQLServer as NEW SQLDMO.SQLServer
dim objDatabase as AQLDMO.Database
objSQLServer.Connect"sqlserverl","dbdev","devpw"
For Each objDatbase in objSQLServer.Databases
Magbox"Database name:"&objDatabase.Name
Next
Set oSSQLServer=Nothing
从这段程序可以看出,首先,SQL Server对象的使用实现了与服务器的连接,其次,可使用Connect方法建立与服务器的连接。此例中的服务器名为SQL SERVER1,用户ID和口令分别为DBDEV和DEVPW。
@ 如果遗漏了对用户名和口令的引用,应用软件在执行时会加以提示。
再次,在for…next循环中,数据库对象的NAME属性显示在信息框中,以表示服务器上可用的每个数据库。
最后,当对象设置为NOTHING时,SQL Server连接将取消。此时将释放连接以及客户端系统上与之相关的对象。
需用户考虑的是SQL-DMO对象上对象、集合、属性和方法的平衡。在执行其他自动对象时可访问它们。另外,还可以使用ExecuteImmdiate和ExecuteWithResults方法向SQL Server发送命令。它们允许直接向服务器发送SQL语句。
数据访问对象(DAO)指一种使数据库的使用更容易的对象、方法和属性。虽然它们仍为SQL Server事务处理使用Jet和ODBC访问层,但在用户、开发人员和实现请求所需的ODBC调用之间增加了抽象层。
借助DAO,可以使用对象集处理数据库、表格和视图等。引用对象上的.ADD方法添加新表比使用标准ODBC方法和引用存储过程更容易。再例如,多数集合都将拥有标准属性集。在下段程序中,.count属性表示当前数据库中的TableDef(表定义)数。
'Determine how many tables there are then are and then puint
'the results.
i=db.TableDefs.Count
Debug/.print "There are" & Str $(i)& in this database.
在使用数据库当中,通过使用这些标准方法可以利用有关要由ODBC访问的任何数据源。另外,这些方法还适用于其他语言和其他环境。例如,可在所有版本的Visual Basic中访问DAO并将在未来版本中支持。
为解决与数据库系统及数据库系统之间的连接,Microsoft开发了ODBC方法。ODBC是应用软件和基本数据库系统间的抽象层。这个层次允许发出一条Select语句,并在任何所支持的数据库中执行它,包括数据库不直接支持SQL语言的某些情况。
ODBC是数据库文件的访问层,接收用户对信息的请求并将其转换成数据库能识别和用于从数据库中提取信息的语音。
ODBC是与应用软件的通用接口,它允许开发通用调用和方法而无需考虑基础数据库的细节。Microsoft Access中就有现成的例子。在Access中,可以选择表格连接或附加到数据库上。Access将提示用户输入想使用的数据库表的类型。用户可以从Access自带的几个格式中直接选择,也可以只选择ODBC。之后屏幕将显示已建立的各种ODBC配置。用户可以自由选择而无需考虑数据库机制。
Access能够将表格连接到数据库,因为它不关心数据库,只关心是否能用标准SQL语句使用数据库,这正是ODBC的关键所在。
由于ODBC的主要目的是提取与基础数据库的会话,因此一旦与数据库连接后ODBC可以说是透明的。这与前面所讲的DB-LIB有所不同,DB-LIB需要特殊语法才能将语句放在缓冲区中并直接与服务器配合,而ODBC只需创建标准SQL语句,然后将该语句关连至ODBC即可。
在应用软件中使用PDBC时,同时会用到它引用的数据源和数据库引擎。如本章稍后将介绍的“客户机配置”一节所讲,安装ODBC时,不仅要安装整个ODBC子系统,还应安装数据库驱动程序组合。首先为这些组合命名,这样当想访问指定的数据库时便能在连接请求中使用。这些数据库和驱动程序组合定义被称为数据源名(DSN)。如果打开ODBC连接但未定义这些信息,ODBC将给出提示。
在多数语言中,当为ODBC指定连接串时,有两种选择。首先,可以定义只是你想打开的ODBC连接,这时ODBC将提示用户确定DSN将作用的信息。
Set db=OpenDatabase("", ,"odbc;")
这种情况下,用户提供的信息将确定要打开的数据库。还可以通过DSN、用户ID和密码等连接特性确定将使用的连接。
Set db=OpenDatabase("", ,"odbc;<DSN Info>")
@ 如果允许用户定义想使用的ODBC连接,应结束使用计划之外的数据库。多数情况下,应用软件将提供有关ODBC允许与数据库连接的DSN信息,以保证用户了解数据库情况,知道正在访问的信息源。
第二种选择是在连接字串本身指明连接细节。在这类连接中,<DSN Info>代表可定义为DSN一部分的任何项。常用项如表20-5所示。
表20-5 通用DSN和连接字串元素
|
元 素 |
说 明 |
|
DSN |
在ODBC设置中配置的DSN名 |
|
UID |
用于注册到数据库的用户ID |
|
PWD |
用于注册的口令 |
例如,请看如下简单的VBA语句:
Set db=OpenDatabase("", ,"odbc;DSN=MyDSN;UID=MyUserName;PWD=MyPassword")
此语句利用MyDSN配置与ODBC数据源相连。它同样使用参数中所列的用户名和口令。执行此命令后用户得不到任何关于ODBC DSN信息的提示,而是自动连接。
在此例中,使用了一些数据访问对象来访问ODBC数据源。借助这种访问方法,可以通过使用常用对象和对象浏览方法处理保存在数据库系统中的表格、域和信息。请看程序清单20-1所示的程序。
程序清单20-1:DAO与ODBC连接的例子
Sub DAOExample()
'set up the variables
Dim db As DATABASE
Dim i AS Integer
'connect to the database
Set db = OpenDatabse("",,"odbc;DSN = BILLING;UID = SA;PWD = ;")
'Determine how many tables there are and then print
'the results.
i = db.TableDefs.Count
Debug.Print "There are "& Str$(i) &"table(s) in this database."
'Close the connection
db.Close
End Sub
此程序的输出将是一个语句,说明数据库中的表格数。借助DAO面向对象的特性,数据连接建立后很容易使用。
使用SQL的最后一步是关闭连接。关闭方法的定义随宿主语言(VB或VBA)的不同而不同,但都可以通过.Close方法关闭。这样将关闭与数据库的连接并释放与连接相关的内存结构。