第五章 连接数据库
在数据库应用程序中,TDatabase构件是很有用的。它能够管理和操纵数据库的连接,控制数据库连接的持续性。TDatabase构件还提供了管理事务和申请更新数据的功能。
第三章已经详细介绍了TSession与TDatabase的关系,所有的数据库连接都在TDatabase构件的控制之下,而所有的TDatabase构件又在BDE会话期对象的管理之下。
5.1 永久和临时的TDatabase构件
很多情况下,其实并没有必要显式地使用TDatabase 构件。当应用程序试图打开一个数据库时,会自动创建一个临时的TDatabase构件。当然,这个临时的TDatabase 构件只在数据库连接期间是有效的,一旦关闭了数据库,这个临时的TDatabase 构件将被删除。
不过,在有的数据库应用程序尤其是两层或多层的Client/Server应用程序中,最好还是显式地使用TDatabase构件。凡是在设计期加到窗体或数据模块上的TDatabase构件,我们称为永久的TDatabase构件,这是相对临时的TDatabase构件而言的。
使用永久的TDatabase构件的好处是,可以建立永久的连接,具有管理事务的能力,可以创建应用程序专用的BDE别名,还可以响应OnLogin事件。
临时的TDatabase构件的功能就有某种程度的局限,它的有些关键属性受制于它所属的BDE会话期对象,例如,BDE会话期对象的KeepConnections属性决定了当所有数据集都关闭后数据库是否继续维持在连接状态。而永久的TDatabase构件的KeepConnections 属性则不受BDE会话期对象的KeepConnections属性的影响。
有时候,往往很难确定到底需要用几个TDatabase构件,而您又不希望用临时的TDatabase构件来代替,这时候,就需要在运行期动态地创建TDatabase构件。
要在运行期动态地创建TDatabase构件,首先要声明一个TDatabase类型的变量,然后调用TDatabase的Create函数来创建TDatabase的对象实例。程序示例如下:
Function RunTimeDbCreate(const DatabaseName, SessionName: string): TDatabase;
var
TempDatabase: TDatabase;
Begin
TempDatabase := nil;
Try
Sessions.OpenSession(SessionName);
With Sessions Do
Begin
With FindSession(SessionName) Do
Result := FindDatabase(DatabaseName);
If Result = nil then
Begin
TempDatabase := TDatabase.Create(Self);
TempDatabase.DatabaseName := DatabaseName;
TempDatabase.SessionName := SessionName;
TempDatabase.KeepConnection := True;
End;
Result := OpenDatabase(DatabaseName);
End;
Except
TempDatabase.Free;
Raise;
End;
End;
可以这样调用RunTimeDbCreate函数:
var
MyDatabase: array [1..10] of TDatabase;
MyDbCount: Integer;
Begin
MyDbCount := 1;
...
MyDatabase[MyDbCount]:=RunTimeDbCreate('MyDb'+IntToStr(MyDbCount),'');
Inc(MyDbCount);
...
End;
5.2 控 制 连 接
无论是永久的TDatabase构件还是临时的TDatabase构件,都可以通过它们的属性、方法和事件来控制有关连接数据库的行为,这也是使用TDatabase构件的主要目的。
5.2.1 指定一个BDE会话期
所有的TDatabase构件都必须指定一个它所属的BDE会话期,这就要用到两个属性,一个是SessionName,另一个是Session。
SessionName属性用于指定一个BDE会话期的名称。当在设计期把一个TDatabase构件放到窗体或数据模块上时,它的SessionName属性自动设为“Default”,这是默认的BDE会话期的名称。如果您已经在窗体或数据模块上放了若干个TSession构件,您就可以从一个下拉列表中选择SessionName属性的值。
Session属性是只读的,用于返回TDatabase构件所属的BDE会话期对象。如果SessionName属性设为空或“Default”,Session属性就返回默认的BDE会话期对象。
通过Session属性返回BDE会话期对象后,您就可以访问TSession的属性、方法和事件,即使您不知道该BDE会话期对象的实际名称。
5.2.2 指定要访问的数据库
要指定一个数据库,就要用到AliasName属性或DriverName属性。这两个属性是互斥的,设置其中一个,另一个就被清空。修改AliasName、DriverName、DatabaseName等属性之前都要先把Connected属性设为False,否则将触发异常。
AliasName属性用于指定一个数据库的别名,只能设为已有的BDE别名如DBDEMOS、DefaultDB、IBLOCAL等。
数据库的别名一般是用SQL Explorer或BDE管理程序定义的。不过,也可以用DatabaseName属性定义一个应用程序专用的别名。DatabaseName属性可以设为一个已有的BDE别名。对于Paradox和dBASE表来说,也可以设为表所在的路径。
用DatabaseName属性定义的别名只限于在本应用程序中使用,它将出现在TTable、TQuery、TStoredProc构件的DatabaseName属性的下拉列表中。
DriverName属性用于指定一个数据库驱动程序的类型,可以设为STANDARD(用于dBASE和Paradox)、MSSQL、INTERBASE、ORACLE、SYBASE、INFormIX等。设置了DriverName属性后,还得设置Params属性指定连接参数。
数据库驱动程序其实是BDE别名的一个参数。因此,设置了AliasName属性后,DriverName就会自动清空。反之,设置了DriverName 属性后,AliasName属性也会自动清空,否则就会出现矛盾。这样看来,DriverName属性似乎作用不大,只要设置AliasName属性就够了。不过,当DatabaseName属性定义一个应用程序专用的别名时,需要设置DriverName属性指定该别名使用什么驱动程序。
在设计期,要指定一个BDE别名或者数据库驱动程序或者定义一个专用的别名,既可以在对象观察器中进行,也可以双击TDatabase构件打开数据库属性编辑器,然后在“Name”框内设置DatabaseName属性的值,在“Alias Name”框内设置Alias属性的值,在“Driver Name”框内设置DriverName属性的值。
也可以在运行期设置DatabaseName、AliasName或DriverName属性的值,例如:
Database1.DatabaseName := Edit1.Text;
5.2.3 设置BDE别名的参数
要设置BDE别名的参数,如路径、服务器名、缓存长度、语言驱动程序、用户名、口令等,就要用到Params属性。
在设计期,要设置BDE别名的参数有三种方式:
一是使用SQL Explorer或BDE Administrator来定义或修改别名以及参数。
二是在对象观察器中单击Params属性边上的省略号按钮打开字符串列表编辑器,然后按格式键入参数的名称和值。
三是双击TDatabase构件打开数据库属性编辑器,如图5.1所示。
图5.1 设置BDE别名的参数
单击“Defaults”按钮将在“Parameter Overrides”框内列出与驱动程序所对应的默认参数,对于dBASE和Paradox来说,默认的参数主要是路径,对于远程服务器来说,默认的参数就多了,包括服务器名、用户名和口令、语言驱动程序等。
单击“Clear”按钮可以把“Parameter Overrides”框实际上就是Params属性清空。
可以直接在“Parameter Overrides”框内修改参数,也可以添加新的参数。
要在运行期设置BDE别名的参数,就要用到TStrings对象。从图5.1也可以看出,Params属性实际上是一个字符串列表,每个字符串的格式是“名称=值”。程序示例如下:
With Database1 Do
Begin
Params.Clear;
Params.Add('UserName = Sysdba');
Params.Add('Password = 1234');
LoginPrompt := False;
Open;
End;
5.2.4 登录到服务器
大多数服务器都有严密的安全措施,以防止未授权的访问。对于用户来说,他面临的第一道关卡就是登录,即输入用户名和口令。
在设计期,当试图连接一个远程服务器时,Delphi 4会推出一个标准的登录对话框,让您输入用户名和口令。
在运行期,有三种方式进行登录:
第一种方式是把LoginPrompt属性设为True,这样,当需要连接远程服务器时,就会自动弹出一个标准的登录对话框,让用户输入用户名和口令。
第二种方式是把LoginPrompt属性设为False,并且设置Params属性,其中应包含“USER NAME”和“PASSWORD”参数,例如:
USER NAME=SYSDBAPASSWORD=masterkey
注意:在程序中通过代码提供用户名和口令容易泄密,建议最好不要用这种方式。
第三种方式就是在处理OnLogin事件的句柄中设置LoginParams参数,程序示例如下:
LoginParams.Values['USER NAME'] := UserName;
LoginParams.Values['PASSWORD'] := PasswordSearch(UserName);
当退出处理OnLogin事件的句柄时,LoginParams参数的值就被赋给Params属性。
5.2.5 开始连接数据库服务器
要开始连接数据库服务器,可以调用Open函数或者把Connected属性设为True。实际上,把Connected属性设为True会自动调用Open。此时,会触发OnLogin事件。如果程序没有处理OnLogin事件,就会弹出一个标准的登录对话框让用户登录。
如果在没有连接服务器的情况下试图打开一个数据集,将首先调用Open函数连接服务器,并根据需要自动创建一个临时的TDatabase构件。
一旦与服务器建立了连接,只要至少有一个数据集是活动的,连接就会一直保持。如果所有的数据集都不处于活动状态,是否断开连接取决于KeepConnections属性的值。
如果KeepConnections属性设为True,即使没有一个数据集处于活动状态,也保持连接,对于那些频繁地打开和关闭数据集的应用程序来说,可以避免老是登录。如果KeepConnections属性设为False,当所有的数据集都关闭了时,将断开与服务器的连接。
要断开连接,就要调用Close或者把Connected属性设为False。实际上,把Connected属性设为False会自动调用Close。
Close会自动关闭所有的数据集,然后断开连接。如果只想关闭所有的数据集,但不想断开连接,首先要把KeepConnections属性设为True,然后调用CloseDataSets函数。
注意:即使KeepConnections属性设为True,调用Close函数总是能断开连接。
5.2.6 网络协议和ODBC
Delphi 4用BDE和SQL Links驱动程序来连接数据库服务器,其中,BDE还可以驱动ODBC访问更广泛的数据源。
在配置SQL Links和ODBC驱动程序时要注意网络协议的问题。大部分情况下,网络协议由数据库服务器的客户端软件来配置,但对于ODBC来说,还需要在专门的ODBC管理程序中配置网络协议。
刚开始连接服务器时往往很难成功,这时候首先要检查客户端软件是否正确配置,如果使用TCP/IP协议的话,要检查是否安装了支持TCP/IP协议的软件如WINSOCK.DLL,服务器的IP地址是否在客户端的HOSTS文件中注册,域名服务是否正确配置。
5.3 遍历一个数据库的所有数据集
TDatabase构件的DataSets属性和DataSetCount属性配合起来使用可以遍历一个数据库的所有数据集。
DataSets属性是一个数组,它的每一个元素是一个活动的数据集如TTable、TQuery或TStoredProc,每个数据集都可以通过序号来访问。
DataSetCount属性返回DataSets数组中元素的个数,程序示例如下:
var
I: Integer;
Begin
For I := 0 to DataSetCount - 1 Do
If DataSets[I] is TTable then
DataSets[I].CachedUpdates := True;
End;
5.4 TDatabase与TSession的关系
TDatabase构件主要用于管理数据库的连接,而TSession则用于对一个应用程序中的TDatabase构件进行全局控制,包括临时的TDatabase构件。
TSession的方法往往是针对所有的TDatabase构件的,它不考虑TDatabase构件的状态。例如,TSession的DropConnections函数将关闭所有的数据集,并断开所有的数据库,即使这些TDatabase构件的KeepConnections属性设为True。
而TDatabase只能管理它所连接的数据库,例如,TDatabase的CloseDataSets函数只关闭某个数据库的所有数据集,不关闭其他数据库的数据集。