导航书艺文学网>>电脑书籍>>网页制作>>ASP教程>>ASP 中的数据库组件

书艺文学网

ASP 中的数据库组件
第五部分  数据库组件
     本部分内容
     Activex 数据对象
     操作记录集
     使用命令
第22章 
Activex数据对象
本章内容
Activex数据对象概述
使用Activex数据对象
使用连接对象

 这一章介绍Activex数据对象(ADO)。第一节是这些对象的概述。第二节一步一步地引导你使用ADO从数据库中读取数据和向数据库中存储数据。最后,在第三节,将向你介绍一种特殊的重要的ADO对象:连接对象。

Activex数据对象概述
使用Activex数据对象(ADO),你可以对来自许多种数据提供者的数据进行读取和写入操作。例如,你可以使用ADO来访问Microsoft Access,Microsoft SQL和Oracle数据库中的信息。你甚至可以使用ADO从Microsoft Excel表格中读取信息。
在这本书里,你将学习如何使用ADO操作Microsoft SQL Sever数据库。所有的例子都假定你是在使用这种数据库。但是,你应该知道,你在下面几章中学到的大部分内容对其它类型的数据库也是适用的。
在第三部分“操作数据:SQL”中,你学习了如何适用结构化查询语言(SQL)。从这一章开始,你将很好地应用第三章所学的知识。学习的重点是结合ADO,使用SQL对一个数据库进行读写操作。ADO和SQL的的这种结合是功能很强大的。

注:
要了解Activex数据对象的方法,属性,和集合的详细内容,请参考书后的附录A,“ASP对象和组件快速参考”。

Activex数据对象共有七种独立的对象。下面列出了这七种对象的名字,并简要介绍了它们的功能:
■ 连接对象。代表与一个数据源的唯一对话。例如,你可以用连接对象来打开一个对Microsoft SQL Sever的连接。
■ 记录集对象。代表来自一个数据提供者的一组记录。例如,你可以用一个记录集对象来修改一个SQL Sever表中的记录。
■ 域对象。代表一个记录集中的一个域。
■ 命令对象。代表一个命令。例如,你可以用命令对象执行一个SQL存储过程或有参数的查询。
■ 参数对象。代表SQL存储过程或有参数查询中的一个参数。
■ 属性对象。代表数据提供者的具体属性。
■ 错误对象。代表ADO错误。

使用Activex数据对象
这一节将一步一步地引导你在你的ASP网页中使用ADO。首先你将学习如何配置你的服务器以使用ADO。接着,在下一节提供了一个简单的例子,演示如何使用ADO对数据库进行读写操作。最后,考虑到你会遇到一些问题,有一节内容讲述ADO的调试。

配置服务器以使用Activex数据对象
本书假定你是在Microsoft SQL Sever中使用ADO。在继续下面的内容之前,Microsoft SQL Sever必须与你的Web服务器安装在同一台机器上,或者两台机器在同一个网络中。要了解安装和配置Microsoft SQL Sever的详细内容,请参阅第三章“安装和使用SQL Sever”。
在能够使用ADO之前,你必须先建立一个数据源。数据源包含了如何与一个数据提供者进行连接的信息。在这种情况下,你将使用数据源与Microsoft SQL Sever建立连接。数据源共有三种类型:你可以建立用户数据源,系统数据源,或者文件数据源。当你要建立一个与Web服务器一起使用的数据源时,你应该建立一个文件数据源。建立文件数据源的好处是连接信息存储在一个实际的文件中。不止一个用户可以访问这个文件。而且,如果你需要把Web应用程序从一种Web服务器移植到另一种Web服务器上,你只需要移植这个文件即可。

注:
在建立一个数据源之前,应确保SQL Sever正在运行。通过MS SQL Sever程序组中的SQL服务管理器可以确定SQL服务是否在运行。

按如下步骤可以建立一个新的文件数据源:
1. 打开WINDOWS NT SEVER的控制面板(选择Start|Setting|Control Panel)。
2. 单击ODBC的图标。
3. 单击标签File DSN。
4. 单击按钮Add,出现Create New Data Source对话框。
5. 在对话框中,选择SQL Sever驱动程序并单击按钮Next,出现Create a New Data Source对话框。
6. 输入你所建的数据源的名字。例如,输入mydata.dsn。单击Next,再单击Finish,则wizard程序Create a New Data Source to SQL Sever会被启动(见图22.1)。
 

   图22。1

7. 在文本框Description中,输入一个描述,如My Data Source。在文本框Sever中,输入安装了SQL Sever的服务器的名字。(如果SQL Sever与Web服务器安装在同一台机器上,你可以输入Local)单击Next。
8. 一系列对话框出现,要求你定制数据源的各种属性。你要指定一个缺省数据库。选择你的表所在的数据库作为缺省数据库。让其它的选项保持其缺省值,单击Next,关闭所有的对话框。
9. 最后,给你一个测试新数据源的机会。如果测试成功了,单击OK,添加这个新数据源。
  你已经建立了一个名为mydata.dsn的新数据源。你可以使用这个数据源连接到Microsoft SQL Sever.(下一节将介绍如何进行连接)

使用Activex数据对象对数据库进行读写
这一节给出了一个如何使用ADO对Microsoft SQL Sever数据库进行读写操作的例子。举这个例子有两个目的:它演示了从ASP网页中访问Microsoft SQL Sever的基本方法,而且你可以用这个例子检测服务器的配置是否正确。
表22.1所示的网页把文本“Hello World!”插入一个表中,然后,从表中取出这个文本并显示在浏览器中。

表22.1   Hello World!
<% Set MyConn=Server.CreateObject("ADODB.Connection") MyConn.Open "FILEDSN=d:\Program Files\Common Files\ODBC\Data Sources\MyData.dsn" MyConn.Execute "INSERT MyTable (MyColumn) VALUES ('Hello World!')" Set RS=MyConn.Execute("SELECT * FROM MyTable") Response.Write(RS("MyColumn")) MyConn.Close %>

在使用这个例子之前,你需要建立一个名为Mytable的表。你可以使用ISQL/w来创建它。启动这个程序,选择你的缺省数据库,然后执行如下的SQL 语句:

CREATE TABLE mytable (mycolumn VARCHAR(255))

注:
要了解建立表的更多信息,请参见第10章“SQL基础”。

这个网页的第一行创建了连接对象的一个实例。接下来调用连接对象的open方法,打开了一个对数据库的连接。在open方法中用到了你在上一节所建立的数据源,以建立对数据库的连接。(用你的计算机中的实际路径代替这个脚本中文件数据源的路径。)
一旦打开了一个连接,你就可以用这个连接执行SQL语句。在这个例子中,用Execute方法执行了两个SQL语句。首先,用SQL INSERT语句把字符串“Hello World!”输入到了数据库中。然后用SQL SELECT语句从表中取出了这个字符串。
如果你的系统配置正确,字符串“Hello World!”将会显示在浏览器窗口中。该字符串先被插入数据库,又被取出并显示。如果有什么不正常,请参看下一节。

调试Activex数据对象
如果你用ADO访问Microsoft SQL Sever时出现问题,这一节将对你有所帮助。许多原因会导致上一节中所示的ASP网页执行失败。下面列出了你通常会遇到的一些问题的症状以及可能的原因:

■ 症状:出现错误信息 Unable to create file buffer.
原因:文件数据源不正确。如果文件数据源的路径或名字有误,或者该数据源不存在,你就会收到这个错误信息。你应确保网页中open方法所使用的文件数据源的路径与你计算机中的实际路径相同。

■ 症状:出现错误信息 Invalid object name 'mytablw'
原因1:数据库中不存在表'mytable'。按照上一节中所讲的方法用ISQL/w创建这个表。
原因2:表mytable不在缺省数据库中。你需要指定一个缺省数据库。选择Start|Settings|Control Panel。单击ODBC图标,然后单击File DSN标签。选择你的文件数据源的名字,单击Configure,再单击Options。在对话框中指定你的确省数据库的名字。

■ 症状:出现错误信息 The sever appears to be not available
原因:SQL Sever没有运行。从Microsoft SQL Sever程序组中选择SQL Sevice Manager。选择MSSQLSEVER并单击绿灯。

■ 症状:出现错误信息 Login failed。
原因:你没有使用WINDOWS NT确认模式。建立数据源时输入了错误的帐号和口令。选择Start|Settings|Control Panel。单击ODBC图标,然后单击File DSN标签。选择你的文件数据源的名字并单击Configure。你可以选择Use Trusted Connection,或输入合法的帐号和口令。

■ 症状:出现错误信息 INSERT permission denied on object mytable 或
           SELECT permission denied on objict mytable。
原因:建立数据源时指定的帐号没有访问表mytable的足够的权限。你需要改变文件数   据源的注册帐号,或者给该用户或用户组提供更多的权限。

  要提供对一个表的更多权限,从Microsoft SQL Sever程序组中启动SQL事务管理器,找到表mytable并用右键点击它。选择Permissions。现在你可以为不同的用户或用户组设置对这个表的操作权限。

使用连接对象
与数据库的所通信都要通过一个打开的连接来进行。在对一个数据库进行数据的插入和读取之前,必须先打开与这个数据库的连接。这种打开和关闭一个连接的操作与打电话的过程有相似之处。在你能够与SQL Sever进行通信之前,你必须先呼叫它。
这一节讲如何使用ADO连接对象。首先你将学习如何打开和关闭一个对数据库的连接。接下来,你将学会如何通过一个打开的连接执行SQL语句。最后,你将学习如何用连接对象创建事务处理。

打开和关闭数据库连接
要打开与一个数据库的连接,你可以创建连接对象的一个实例。创建了这个实例之后,你就可以调用连接对象的open方法,打开一个连接。这里有一个例子:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\Common Files\ODBC\Data Sources\MyData.dsn"
MyConn.Execute "INSERT Mytable (mycolumn) VALUES ('Hello World!')"
MyConn.Close
%>

在这个例子中,创建了连接对象的一个实例MyConn。然后调用连接对象的open方法。接下来,调用连接对象的Execute方法,执行了一个SQL语句。最后,关闭这个连接。
每次打开一个新连接时都要输入文件数据源的路径和名字,这实在是个另人厌烦的工作。你可以把这个字符串分配给一个session变量或者在一个包含文件中把它定义为一个常量。这样,你只需要键入一个变量名即可,而不必输入文件数据源的完整名称。要定义一个包含有文件数据源名字的session变量,你可以在文件Global.asa中定义。例如,你可以把下面的内容添加到文件Global.asa的session_onstart脚本中:

session("connectionstring")="FILEDSN=d:\Program Files\Common 
              Files\ODBC\Data Sources\MyData.dsn"

注:
要了解使用session变量的更多信息,请参阅第16章“使用Active Sever Pages Sessions”。

建立了这个session变量后,你就可以用如下的脚本打开一个连接:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open Session("connectionstring")
%>

把文件数据源的名字分配给一个session变量的另一个好处是,你将来可以很容易地改变数据源。如果你需要使用另外一个数据源,你只要改变文件Global.asa中的一个session变量的值即可。
使用完一个连接后,你应该关闭它。这就象挂断一个电话,从而释放占用的线路。连接对象的close方法可以关闭一个连接。关闭了一个连接后,你就不能在用这个连接与数据库进行通信。因此,依赖这个连接支持的其它对象也不能再与数据库相通信。

通过打开的连接执行SQL语句
通过打开的连接执行SQL语句,要用到Execute方法。这个方法有两种形式:一种形式用来从数据库中返回信息,当不需要返回信息时,则使用另一种形式。
下面的例子演示了如何使用Execute方法执行一个没有返回结果的SQL语句:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\Common Files\
       OBDC\Data Sources\MyData.dsn"
MyConn.Execute "INSERT Mytable (MyColumn) VALUES('Hello World!')"
MyConn.Close
%>

在这个例子中,用Execute方法执行了一个SQL SELECT 语句。因为没有返回结果,Execute方法不使用括号。
你也可以用Execute方法从一个查询返回结果。如下例所示:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data  Sources\MyData.dsn"
Set RS=MyConn.Execute("SELECT * FROM Mytable")
MyConn.Close
%>

在这个例子中,使用了Execute()方法以返回一个SQL SELECT查询的结果。与上一个例子不同,这个Execute方法使用了括号。当你要返回结果时,千万别忘了使用括号,否则你会收到错误信息 Expected end of statement.
这个SQL查询的结果被读取到记录集对象的一个实例RS中。该记录集由Execute()方法自动创建。你将在下一章中学习如何使用记录集。
Execute方法包含两个可选参数。你可以给一个RecordsAffected参数,用来保存被执行的SQL语句所操作的记录个数。你还可以给一个Options参数,用来提供被执行的SQL语句的有关信息。下面的例子同时使用了这两种可选参数:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn" 
MyConn.Execute "UPDATE Mytable Set Mycolumn='Goodbye!'",HowMany,adCMDText
Response.Write(HowMany)
MyConn.Close
%>

在这个脚本中,执行了一个SQL UPDATE语句,改变了表Mytable中所有记录的值。Execute方法带有两个参数。第一个参数是RecordAffected参数。在这个例子中,变量HowMany被作为RecordAffected参数。这个SQL语句执行后,变量HowMany中将存有该语句所操作的记录数。例如,如果表中有32条记录被更新,变量HowMany的值将是32。
上例中Execute方法的第二个参数是Options参数。在这个例子中,Options参数被指定为常量adCMDText。这个常量用来告诉ADO,它应该把字符串的内容解释为命令文本,而不是一个表的名字或一个存储过程。通过告诉ADO被执行的字符串的内容的有关信息,这个常量使得ADO更高效地执行这个命令。(要了解命令的更多信息,请参见第24章“使用命令”。)
你可以使用下面的常量作为Options参数:

■ adCMDTable。被执行的字符串包含一个表的名字。
■ adCMDText。被执行的字符串包含一个命令文本。
■ adCMDStoredProc。被执行的字符串包含一个存储过程名。
■ adCMDUnknown。不指定字符串的内容。(这是缺省值。)

  在你能够在一个ASP网页中使用这些常量之前,你必须先包含一个名为ADOVBS.inc的特殊文件。文件ADOVBS.inc中包含ADO使用的所有VBSript常量。上例中第一行的INCLUDE语句包含了文件ADOVBS.inc。
在你安装ASP时,这个文件应该已经被自动安装了。一般来说,它会被安装在c:\Program Files\Common Files\System\ADO目录下。但是,你也许不得不使用WINDOWS NT任务栏中的Find命令,找到这个文件的确切位置,找到它之后,把这个文件拷贝到你的Active Sever Pages目录中。

注:
如果你使用Jscript,而不是VBSript,ADO常量的包含文件应该是ADOJAVAS.inc。

打开一个连接后,你需要调用Execute方法多少次,你就可以调用多少次。
例如,下面的脚本向表Mytable中输入了32个字符串:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn" 
FOR i=1 TO 32
MySQL="INSERT Mytable (Mycolumn) VALUES (' This is entry "&i&" ')"
MyConn.Execute MySQL, HowMany,adCMDText
NEXT
MyConn.Close
%>

这段脚本使用了一个FOR......NEXT循环,向表Mytable中插入了32条记录。变量MySQL包含Execute方法使用的SQL命令字符串。注意书写SQL字符串时如何使用单引号和双引号。单引号用来标记SQL语句内部的引用。双引号用来指定VBSript内字符串的开始和结束。
用Execute方法几乎可以这些所有的SQL命令。例如,下面的脚本创建了一个表,然后添加数据,清除数据,最后删除这个表:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn" 
' create a new table
MySQL="CREATE TABLE newtable (mycolumn VARCHAR(255))"
MyConn.Execute MySQL
' populate the table
MySQL="INSERT newtable (mycolumn) VALUES('hello')"
MyConn.Execute MySQL
'truncate the table
MySQL="TRUNCATE TABLE newtable"
MyConn.Execute MySQL
'drop the table
MySQL="DROP TABLE newtable"
MyConn.Execute MySQL
Myconn.Close
%>

创建事务处理
当一组语句构成一个事务处理时,如果一个语句没有执行成功,则所有的语句都不成功。如果你需要更新多个表中的数据,你不希望对一个表的操作失败,而对其它表的操作成功了。这时所有事务处理是有用的。
例如,假设某个时间有人在你的站点上买了东西,有关的交易信息存储在两个表中。一个表用来保存买者的信用卡信息,另一个表包含了要买的商品的信息。
现在,假如有一个人正试图从你的站点上买东西。他的信用卡号码已经输入了第一个表中。但是,就在这时,发生了意外情况,一道闪电击中了你的服务器,使第二个表没有被更新。在这种情况下,当然最后是两个表都没有被更新过。你当然不想收这个人的钱去买他不想买的东西。使用事务处理,你可以防止第二个表没有被更新而第一个表被更新的情况出现:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn" 
MyConn.BeginTrans
MyConn.Execute "INSERT CreditCard (CCNum) VALUES ('5555-55-444-44-4444')"
MyConn.Execute "INSERT Shipping (Address) VALUES('Paris,France')"
MyConn.CommitTrans
MyConn.Close
%>
在这个例子中,用BeginTrans方法和CommitTrans方法来标记事务处理的开始和结束。在BeginTrans方法被调用之后,CommitTRans方法被调用之前,不管出现什么错误,两个表都不会被更新。
你也可以恢复一个事务处理的操作(操作作废)。要做到这一点,应使用RollBackTrans方法。考虑如下的脚本:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn" 
MyConn.BeginTrans
MyConn.Execute "INSERT CreditCard (CCNum) VALUES ('5555-55-444-44-4444')"
MyConn.Execute "INSERT Shipping (Address) VALUES('Paris,France')"
IF WEEKDAYNAME(WEEKDAY(DATE))="Sunday" THEN
  MyConn.RollBackTrans
ELSE
  MyConn.CommitTrans
END IF
MyConn.Close
%>

在这个例子中,使用了RollBackTrans方法,如果是星期天,就取消事务处理所做的操作。在星期天两个表都不能被更新。
 

总结:
  这一章介绍了Activex数据对象。第一节是ADO的概述。在第二节,你学会了如何配置服务器以使用ADO。最后,向你介绍了最重要的ADO对象之一:连接对象。
 
 

第23章 使用记录集
           本章内容
           用记录集显示记录
           记录集游标和锁定类型
           操作记录集的高级方法

  在第22章“Activex数据对象”中,你学习了如何使用ADO连接对象打开一个数据库连接。你还学习了如何用一个打开的连接执行SQL命令和返回记录集。但是,操作记录集对象的方法并没有讨论。
这一章讲述如何使用记录集对象。在第一节,你将学习用这种对象显示数据的基本方法。在第二节,你将学习如何用各种不同类型的游标和锁定打开一个记录集。最后,第三节讲述了许多操作记录集中记录的高级方法。

用记录集显示记录
记录集可以用来代表表中的记录。与表一样,一个记录集包含一条或多条记录(行),每个记录包括一个或多个域(字段)。在任何时刻,只有一条记录是当前记录。
要创建记录集对象的一个实例,你可以使用连接对象的Execute()方法。当你用Execute()方法从一个数据库返回查询结果时,一个记录集对象会被自动创建。这里有一个例子:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn" 
Set RS=MyConn.Execute("SELECT * FROM Mytable")
RS.Close
MyConn.Close
%>

在这个例子中,使用一个SQL SELECT语句从一个表Mytable中返回了所有的记录。Execute()方法返回一个记录集。在这个脚本中,该记录集被分配给变量RS,然后关闭了这个记录集。最后,关闭与数据库的连接。
记录集中的每一条记录都对应于表Mytable中的一条记录。要显示记录集中的所有记录,你只要简单地做一个循环就可以,如下例所示:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn" 
Set RS=MyConn.Execute("SELECT * FROM Mytable")
WHILE NOT RS.EOF
  Response.Write("
"&RS("Mycolumn"))
  RS.MoveNext
WEND
RS.Close
MyConn.Close
%>

在这个例子中,WHILE......WEND循环用来扫描记录集RS中的每一条记录,把每个记录的Mycolumn域输出到浏览器。这段脚本显示了表Mytable中的所有记录。
当一个记录集对象中收集了数据时,当前记录总是第一条记录。在上面的例子中,调用了记录集对象的MoveNext方法,使当前记录移到下一条记录。当所有的记录都显示完时,记录集对象的EOF属性的值将变为true,从而退出WHILE......WEND循环。
一个记录集对象有一个域集合,包含一个或多个域对象。一个域对象代表表中的一个特定的字段。例如,在上面的脚本中,使用了表达式RS("Mycolumn")来显示字段Mycolumn。实际上,你可以通过许多中途径显示一个字段的值。下面的每一个表达式都可以显示字段Mycolumn的值:

RS("Mycolumn")
RS(0)
RS.Fields("Mycolumn")
RS.Fields(0)
RS.Fields.Item("Mycolumn")
RS.Fields.Item(0)

注意你既可以通过字段名,也可以通过顺序号来指定一个字段。例如,你可以使用RS("Mycolumn")或RS(0)来代表字段Mycolumn.两种方法起到同样的效果,因为字段Mycolumn对应于表中的第一个字段(第一个字段的顺序号是0)。
当你不知道一个记录集中的字段名时,通过顺序号指定一个域是有用处的。例如,下面的ASP脚本显示了一个表中的所有记录的所有字段(见图23.1):
 
 
 

<%
Set MyConn=Sever.CerateObject("ADODB.Connection")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Source\MyData.dsn"
Set RS=MyConn.Execute("SELECT * FROM Mytable")
%>

 

<% While Not RS.EOF %>

<%
RS.MoveNext
WEND
RS.Close
MyConn.Close
%>


<% FOR i=0 to RS.Fields.Count-1 %>
   
<% =RS(i).Name *>
<% Next %>

<% FOR i=0 TO RS.Fields.Count-1 %>
  
<% = RS(i) %>
<% Next %>


 
 
 
 

图23。1
 
 

在这个例子中,域集合的Count属性用来返回该记录集中的域的数目。Name属性用来返回每个域的名字。两个FOR......NEXT循环用来对记录集中的所有字段进行操作。不论表中有多少记录和字段,它们将被全部显示。

记录集游标和锁定类型
你可以用四种类型的游标打开一个记录集。游标决定了你可以对一个记录集进行什么操作。游标还决定了其他用户可以对一个记录集进行什么样的改变。下面列出了游标的不同类型和限制:

■ adOpenFowardOnly。使用前向游标,你只能在记录集中向前移动。
■ adOpenKeyset。使用Keyset游标,你可以在记录集中向前或向后移动。如果另一个用户删除或改变了一条记录,记录集中将反映这个变化。但是,如果另一个用户添加了一条新记录,新记录不会出现在记录集中。
■ adOpenDynamic。使用动态游标,你可以在记录集中向前或向后移动。其他用户造成的记录的任何变化都将在记录集中有所反映。
■ adOpenStatic。使用静态游标,你可以在记录集中向前或向后移动。但是,静态游标不会对其他用户造成的记录变化有所反映。

  在缺省情况下,当你打开一个记录集时,将用前向游标打开它。这意味着你只能用MoveNext方法在记录集中向前移动。对记录集的其它操作将不受支持。
前向游标的好处是它比较快。无论何时,如果前向游标可以实现你的要求,你就应该使用前向游标。但是,如果你需要用功能更强的游标打开记录集,你可以使用如下的脚本:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT * FROM Mytable",MyConn,adOpenDynamic
RS.Close
MyConn.Close
%>

要用一种特定的游标打开记录集,你必须显式地创建这个记录集。然后用该游标类型打开它。要做到这一点,你首先要创建记录集对象的一个实例。接下来,你要用Open方法,通过一个连接和一种游标类型,打开这个记录集。在这段脚本中,用连接对象MyConn和一个动态游标打开了记录集RS。
打开记录集时,你也可以指定锁定类型。锁定类型决定了当不止一个用户同时试图改变一个记录时,数据库应如何处理。你可以指定下面的四种锁定类型:

■ adLockReadOnly。指定你不能修改记录集中的记录。
■ adLockPessimistic。指定在编辑一个记录时,立即锁定它。
■ adLockOptimstic。指定只有调用记录集的Update方法时,才锁定记录。
■ adLockBatchOptimstic。指定记录只能成批地更新。

在缺省情况下,记录集使用只读锁定。要指定不同的锁定类型,你可以在打开记录集时包含这些锁定常量之一。这里有一个例子:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT * FROM Mytable",MyConn,adOpenDynamic,adLockPessimistic
RS.Close
MyConn.Close
%>

这个脚本与上一个基本相同,只是增加了锁定类型。当打开记录集RS时,将使用adLockPessimistic锁定。这意味着这个记录集中的记录可以被修改。(下一集中将讨论如何修改)
最后,打开一个记录集时,你可以指定一个Options参数。Options参数标明用来打开记录集的命令字符串的类型。告诉ADO被执行的字符串内容的有关信息有助于高效地执行该命令字符串。
你可以使用下面的常量作为Options参数:

■ adCMDTable。被执行的字符串包含一个表的名字。
■ adCMDText。被执行的字符串包含一个命令文本。
■ adCMDStoredProc。被执行的字符串包含一个存储过程名。
■ adCMDUnknown。不指定字符串的内容。(这是缺省值。)

在下面的脚本中,Options参数用来告诉ADO,命令字符串的内容是命令文本:

  
<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT * FROM Mytable",MyConn,adOpenDynamic,adCMDText
RS.Close
MyConn.Close
%>
操作记录集的高级方法
到现在为止,你只学习了如何用SQL来修改记录集中的记录。但是,你还可以使用许多记录集方法修改记录集中的记录。下面列出了每种方法的简要说明:

■ AddNew。向记录集中添加一条新记录。
■ CancelBatch。(当记录集处在批量更新模式时)取消一批更新。
■ CancelUpdate。(调用Update之前)取消对当前记录所做的所有修改。
■ Delete。从记录集中删除一条记录。
■ Update。保存对当前记录所做的修改。
■ UpdateBatch。(当记录集处于批量更新模式时)保存对一个或多个记录的修改。

例如,你可以用AddNew方法向一个打开的记录集中添加一条空记录:

  
<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT * FROM Mytable",MyConn,adOpenDynamic,adCMDText
RS.AddNew
RS("MyColumn")="A new column"
RS.Update
RS.Close
MyConn.Close
%>

在这个脚本中,用AddNew方法创建了一条新记录。接着,新记录的MyColumn域被赋值“A new column”。最后,调用Update方法保存新记录。要使用这些方法,记录集必须以只读方式以外的其它锁定方式打开。
你也可以使用SQL INSERT语句向一个表中添加新记录,以取代AddNew方法。通常,使用SQL比使用上述的方法要好一些,因为SQL更加灵活。本书的其余部分将使用SQL来操作数据库中的数据。

遍历记录集
记录集对象有许多在记录之间移动的方法。这些方法的大部分只有在记录集以某种特定的游标打开时才可以使用。下面列出了记录集对象的一些方法及其功能的说明:

■ Move NumRecords。在记录集中向前或向后移动指定数目的记录数。
■ MoveFirst。移动到记录集的第一条记录。
■ MoveNext。移动到记录集的下一条记录。
■ MovePrevious。移动到记录集中的上一条记录。
■ MoveLast。移动到记录集的最后一条记录。

记录集对象还有许多属性,对遍历记录集是有用处的。同样,许多属性需要特定的游标类型:

■ AbsolutePosition。用来设置或读取当前记录在记录集中的位置顺序号。
■ BOF。标明当前位置在记录集中的第一条记录之前。
■ EOF。标明当前位置在记录集中的最后一条记录之后。
■ RecordCount。表示一个记录集中的记录总数。

例如,假设你想在一个记录集中反向移动,你可以使用MoveLast和MovePrevious方法,以及BOF属性。下面的ASP网页演示了该如何实现:
 
 
 


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT * FROM Mytable",MyConn,adOpenStatic
RS.MoveLast
WHILE NOT RS.EOF
  Response.Write("
"&RS("MyCOlumn"))
WEND
RS.Close
MyConn.Close
%>
 
 

在这个例子中,用静态游标打开记录集。记录集打开后,通过使用MoveLast和MovePrevious方法,该记录集中的所有记录都被显示,直至到达记录集的开头。BOF属性用来检测何时到达记录集的开头。
你可以用这种方法在一个记录集中反向移动,但是,很难想象你有什么理由需要这样做。使用SQL语言自身对查询结果进行排序是有效的。如果你可以,你应该用ORDER BY子句对记录进行排序。(要了解ORDER BY子句的更多内容,请参阅第10章,“SQL基础”)

返回记录数目
你可以用记录集对象的RecordCount属性来确定一个记录集中的记录总数。但是,你应该慎重使用这个属性,因为这个属性在许多情况下效率极低。
对一个用前向游标打开的记录集,你不能使用RecordCount属性。你必须打开一个效率较低的游标才可以使用这个属性,如下例所示:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT Mycolumn FROM Mytable",MyConn,adOpenStatic
Response.Write(RS.RecrdCount)
RS.Close
MyConn.Close
%>

这个脚本输出表Mytable中的记录数目,RecordCount属性用来返回这个数字。为了能使用RecordCount属性,记录集用一个静态游标打开。
通常,你需要一个记录数目的唯一原因是想确定是否至少有一条记录满足特定的条件。例如,你也许想检查一下,是否一个人输入了合法的口令。在这种情况下,你可以查询一个保存口令的表,用RecordCount属性确定是否有口令存在。如果RecordCount大于0,说明有口令存在,否则说明没有,该口令是非法的。
但是,用EOF属性检测一个查询是否返回了结果将会更好。当用前向游标打开了一个记录集时,你可以使用EOF属性。这里有一个例子:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT * FROM Password_Table 
    WHERE Password="&Request.Form("Password"),Myconn
IF RS.EOF THEN
  Response.Write("The password you entered is invalid.")
ELSE
  Response.Write("Welcome to our web site!")
END IF
RS.Close
MyConn.Close
%>

在这个例子中,用EOF属性检测是否一个查询有返回结果。如果EOF属性是true,说明用户输入的口令不在保存口令的表中。
在某些情况下,你的确需要返回记录数目。例如,你也许想显示在你站点上注册的用户总数。但是同样,你应该避免使用RecordCount属性。取而代之,你可以执行一个SQL COUNT(*)查询,如下例所示:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT COUNT(*) Mycount FORM Password_Table",MyConn
%>
There are <% =RS("MyCount")%> registered users at the web site.
<%
RS.Close
MyConn.Close
%>

注意这个查询中如何使用字段别名Mycount。通过给集合函数COUNT(*)提供一个名字,你可以在输入查询结果时使用这个名字。

注:
下一章将讨论用SQL存储过程返回记录数目的方法。参见“在命令对象中使用返回状态值”一节。

对记录集进行分页
假设你想显示你站点上销售的一系列商品。但是,你正在经营几百种项目。在这种情况下,你可能不希望把所有的商品显示在同一个ASP页中。这时允许用户进行翻页将是个不错的办法。
记录集对象有三个属性用于此目的。你可以使用这些属性把一个记录集中的记录分成许多逻辑页。通过把记录集中的记录进行分页,你可以一次只显示记录集中的一部分。下面列出了这些属性:

■ AbsolutePage。指定当前的页。
■ PagePount。返回记录集中的逻辑页数。
■ PageSize。指定一个逻辑页中的记录个数,缺省值是10。

要把一个记录集分成多个页,你应使用PageSize属性指定一页中的记录个数。然后你就可以用AbsolutePage属性移动到一个特定的页。最后,PageCount属性可以用来反回总页数。表23.1演示了如何使用这些属性(见图23.2)。

表23.1 pages.asp
<% ' Figure out the current page IF Request.QueryString("MOVE")="NEXT" THEN  Session("CurrentPage")=Session("CurrentPage")+1 END IF IF Request.QueryString("MOVE")="PREV" THEN  Session("CurrentPage")=Session("CurrentPage")-1 END IF IF Session("CurrentPage")="" THEN  Session("CurrentPage")=1 END IF %>

Current Page: <%=Session("CurrentPage")%>


<% ' Open a Connection and Recordset Set MyConn=Server.CreateObject("ADODB.Connection") Set RS=Server.CreateObject("ADODB.RecordSet") MyConn.Open "FILEDSN=d:\Program Files\Common Files\ODBC\Data Sources\MyData.dsn" ' Retrieve the list of products RS.Open "SELECT ProductName FROM Products", MyConn,adOpenStatic ' Set the number of records in a page RS.PageSize=5 ' Set the current page RS.AbsolutePage=Session("CurrentPage") ' Show the records for the current page WHILE NOT RS.EOF AND NumRows
Product Name: <%=RS("ProductName")%> <% RS.MoveNext NumRows=NumRows+1 WEND %>


<% IF Session("CurrentPage")>1 THEN %> [PREV] <% END IF %> <% IF Session("CurrentPage")[NEXT] <% END IF %> <% RS.Close MyConn.Close %>
 

图23.2
 

这个ASP网页一次显示表Products中的五条记录一个session变量Currentpage被用来跟踪记录集的当前页。当用户单击NEXT时,就显示下一页记录,当用户单击PREV时,就显示上一页。
把记录取到数组中
在特定情况下,你将需要把记录集中的记录取到数组中。例如,如果你需要修改一个记录集中的数据,担你不想改变记录集中的记录本身,这时你可以把记录取到数组中。
要把一个记录集中的记录分配给一个数组,应使用记录集对象的GetRows()方法。这里有一个例子:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.Open "SELECT MyFirstCol,MySecondCol FORM Mytable",MyConn
MyArray=RS.GetRows()
RS.Close
MyConn.Close
%>

在这个脚本中,记录集RS中包含的所有记录被分配给数组MyArray。这个数组由GetRows()方法自动创建并添入数据。GetRows()方法创建了一个二维数组,第一个下标代表字段数,第二个下标代表记录数。
下面的脚本可以用来显示数组MyArray中的内容:

<%
FOR i=0 TO UBOUND(MyArray,2)
%>

First Column:<%=MyArray(0,i)%>

Second column:<%=MyArray(1,i)%>
<%
NEXT
%>

VBScript函数UBOUND()用来确定数组的第二维的维数。FOR......NEXT循环用来扫描数组的所有元素。这个数组代表一个有两个字段的记录集。当该数组的第一个下标值是0时,代表第一个字段,当第一个下标值是1时,代表第二个字段。

指定记录集的最大容量
假设你想显示在你站点上发布的最后10条信息,但是不能超过10条信息。或者你想显示3个连接,但是不超过3个。如何能够限制取到一个记录集中的记录数?记录集对象有一个属性用于此目的。通过使用MaxRecords属性,你可以限制从一个数据库查询返回到一个记录集中的记录数目。如下例所示:

<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
           Common Files\ODBC\Data Sources\MyData.dsn
RS.MaxRecords=10
RS.Open "SELECT MyColumn FROM Mytable",MyConn
WHILE NOT RS.EOF
  Response.Write("
"&RS("MyColumn"))
  RS.MoveNext
WEND
RS.Close
MyConn.Close
%>

在这个脚本中,MaxRecords属性被设为10。当记录集RS被打开时,不会有超过10个记录被取到RS中。即使表中有10,000条记录,也只有10条记录被取出。使用MaxRecords属性时,你必须在打开记录集之前设置该属性值。记录集打开之后,该属性将成为只读的。

总结
  这一章讨论了记录集对象。你学会了如何在ASP网页中使用记录集对象显示表中的数据。你还学会了如何用不同类型的游标和锁定打开记录集。最后,你学习了记录集对象的一些高级方法。

第24章 使用命令

关于Activex数据对象的最后这一章将讲述如何使用命令对象。首先你将学习如何使用命令对象执行有参数的SQL存储过程。其余部分将讲述ADO的两个例子应用程序。首先你将学习为你的站点建立一个高级反馈网页。然后你将学习如何创建一个密码保护系统。

使用命令对象
命令对象代表一个命令(例如,一个SQL查询或一个SQL存储过程)。第22章,“Activex数据对象”,和第23章,“使用记录集”,分别介绍了如何用连接对象的Execute方法和记录集对象的Open方法执行命令字符串。考虑下面这两个例子:

RS.Open "SELECT * FROM Mytable",MyConn

MyConn.Execute "UPDATE Mytable SET Mycolumn='Hello'"

这两个例子都使用了SQL命令字符串。在第一个例子中,用命令字符串打开记录集。在第二个例子中,执行命令字符串来更新数据。
代替命令字符串,你可以使用命令对象。命令对象可以用来代表一个专门的命令。你可以用命令对象的一个实例返回记录集或执行一个不返回记录集的SQL命令。这里有一个例子:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set MyCommand=Sever.CreateObject("ADODB.Command")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn
Set MyCommand.ActiveConnection=MyConn
MyCommand.CommandText="UPDATE Mytable SET Mycolumn='Hello'"
MyCommand.CommandType=adCMDText
MyCommand.Execute
MyConn.Close
%>

在这个例子中,创建了命令对象的一个实例。接着,ActiveConnection属性把命令和一个打开的连接联系在一起。(用Set语句完成这个任务,因为你是在分配一个对象。)CommandText属性指定要执行什么SQL语句。CommandType属性指明该命令是一个命令的文本定义。最后,调用Execute方法执行这个命令。
在这个例子中,命令对象用来返回一个记录集。但是,使用命令对象,你可以通过两种途径返回记录集。这是第一种途径:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set MyCommand=Sever.CreateObject("ADODB.Command")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn
Set MyCommand.ActiveConnection=MyConn
MyCommand.CommandType=adCMdText
MyCommand.commandText="SELECT * FROM Mytable"
Set RS=MyCommand.Execute()
RS.Close
MyConn.Close
%>

在这段脚本中,命令对象的Execute()方法被用来返回一个记录集。注意引号的使用,因为该方法被用来返回结果。用命令对象创建了记录集对象的一个实例后,你可以用标准的方式操作它。
你也可以和一个已经存在的记录集一起使用命令对象,象这样:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set MyCommand=Sever.CreateObject("ADODB.Command")
Set RS=Sever.CreateObject("ADODB.RecordSet")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn
Set MyCommand.ActiveConnection=MyConn
MyCommand.CommandType=adCMdText
MyCommand.commandText="SELECT * FROM Mytable"
  RS.Open MyCommand,adOpenStatic,adLockOptimstic
RS.Close
MyConn.Close
%>

用命令对象打开一个已经存在的记录集对象的好处是你可以指定记录集的游标和锁定类型。在这个例子中,命令对象用来打开一个使用静态游标和adLockOptimistic锁定的记录集。注意打开记录集时如果使用了命令对象,那么你不需指定连接对象,命令对象决定该使用哪个连接。
上面的例子讲述了如何使用命令对象。但是没有讲述为什么要使用连接对象。为什么你要专门创建一个命令对象,而不使用命令字符串呢?
使用命令对象有一个主要的优点。你可以和命令对象一起使用SQL存储过程。

使用SQL存储过程有什么好处
第12章,“高级SQL”,讲述了如何创建SQL存储过程。当你建设好一个站点后,把尽可能多的SQL命令转换为存储过程是个好主意。与其在ASP网页内部执行SQL查询,不如调用包含这些查询的存储过程。
使用SQL存储过程的理由有很多:
  ■SQL存储过程执行起来比SQL命令文本快得多。当一个SQL语句包含在存储过程中时,服务器不必每次执行它时都要分析和编译它。
  ■你可以在多个网页中调用同一个存储过程。这使你的站点易于维护。如果一个SQL语句需要做某些改动,你只要做一次即可。
  ■你可以在存储过程中利用Transact-SQL的强大功能。一个SQL存储过程可以包含多个SQL语句。你可以使用变量和条件。这意味着你可以用存储过程建立非常复杂的查询,以非常复杂的方式更新数据库。
  ■最后,这也许是最重要的,在存储过程中可以使用参数。你可以传送和返回参数。你还可以得到一个返回值(从SQL RETURN语句)。
简而言之,能用存储过程就要用存储过程。存储过程有着极大的优点

使用命令对象调用存储过程
假设你想取出表Mytable中的所有记录并在一个ASP网页中显示它们。而且,假设你想以尽可能高效的方式从表中取出记录。在这种情况下,你应该使用存储过程。
要建立应该新的存储过程,从Microsoft SQL Sever程序组中启动ISQL/w。然后,在查询窗口中输入以下的文本:

CREATE PROCEDURE sp_myporc AS
SELECT * FROM Mytable

单击执行查询按钮(看起来象一个绿色三角形),建立这个存储过程。该存储过程的名字是sp_myproc。
要在一个ASP网页中调用sp_myproc,你可以使用命令对象的一个实例。这里有一个例子:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set MyCommand=Sever.CreateObject("ADODB.Command")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn
Set MyCommand.ActiveConnection=MyConn
MyCommand.CommandType=adCMdStoredProc
MyCommand.commandText="sp_myproc"
Set RS=MyCommand.Execute()
WHILE NOT RS.EOF
  Response.Write("
"&RS("Mycolumn"))
  RS.MoveNext
WEND
RS.Close
MyConn.Close
%>

这段脚本通过调用存储过程sp_myproc取出记录,显示了表Mytable中的所有记录。当你用命令对象调用存储过程时,你应该把该命令对象的CommandType属性设为adCMDStoredProc。CommandText属性用来指定要调用的存储过程。

使用返回状态值
你可以用命令对象从一个存储过程得到返回状态值。例如,假设你想统计一个表中的记录总数。效率最高的方法是建立一个存储过程,如下例所示:

CREATE PROCEDURE sp_CountMytabe AS
RETURN(SELECT COUNT(*) FROM Mytable)

这个存储过程返回表Mytable中的记录总数。SQL集合函数COUNT()计算该表中的记录数。RETURN语句返回这个数。
要得到一个存储过程的返回状态值,你必须为命令对象建立一个参数。命令对象有一个名为Parameters的集合,是一个参数对象的集合。
你可以用命令对象的CreateParameter()方法建立一个参数。接下来,用Append方法把这个参数添加到命令对象的Parameters集合中。这里有一个例子:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set MyCommand=Sever.CreateObject("ADODB.Command")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn
Set MyCommand.ActiveConnection=MyConn
MyCommand.CommandType=adCMdStoredProc
MyCommand.CommandText="sp_CountMytable"
Set MyParam=Mycommand.CreateParameter("RetVal",adInteger,adParamReturnValue)
MyCommand.Parameters.Append MyParam
MyCommand.Execute
%>
There are <%=MyCommand("RetVal")%> records in Mytable.
<%
MyConn.Close
%>

在这个脚本中,用CreateParameter()方法建立了一个参数对象。此例中CreateParameter()方法有三个参数:

■ 第一个参数为新参数指定一个名字。
■ 第二个参数指定数据类型。
■ 最后,第三个参数指定新参数的类型。在此例中,常量adParamReturnValue指明该参数是一个返回参数。

建立了任何新参数之后,都必须把它添加到命令对象的Parameters集合中。Append方法用来把新参数添加到这个集合中。
命令执行后,参数的值可以被取出。因为该参数是命令对象的Parameters集合中的一员,用MyCommand("RetVal")可以返回该参数的值。实际上,用以下的任何一个表达式都可以得到这个值:

MyCommand("RetVal")
MyCommand(0)
MyCommand.Parameters("RetVal")
MyCommand.Parameters(0)
MyCommand.Parameters.Item("RetVal")
MyCommand.Parameters.Item(0)

这些方法都可以用来取出一个参数的值,因为一个参数是命令对象的参数集合的一部分。注意,对所有的集合,你都可以通过名字或顺序号指定一个参数。

使用输出参数
上一节的例子演示了如何得到返回状态值。从一个存储过程取出输出参数值与此非常相似。使用输出参数的好处是输出参数可以有一个或多个。而且,输出参数可以是任何数据类型。
比如有一个表Webusers保存了在你站点上注册的用户的名字。这个表只有一个字段UserName。现在假设你想取出按字母顺序排在最前和最后的用户名。你可以使用下面的存储过程:

CREATE PROCEDURE sp_HighAndLow
(@HighUser VARCHAR(30) OUTPUT,@LowUser VARCHAR(30) OUTPUT)
AS
SELECT @HighUser=MAX(UserName) FROM Webusers
SELECT @LowUser=MIN(UserName) FROM WebUsers

这个存储过程有两个输出参数,@HighUser和@LowUser。@HighUser包含按字母顺序排在最后的用户名(例如,Zeek Zimmerman)。@LowUser包含按字母顺序排在最前的用户名(例如,Anne Arnold)。
要在ASP网页中调用这个存储过程,你可以使用如下的脚本:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set MyCommand=Sever.CreateObject("ADODB.Command")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn 
Set MyCommand.ActiveConnection=MyConn
MyCommand.CommandType=adCMdStoredProc
MyCommand.CommandText="sp_HighandLow"
Set MyFirstParam=MyCommand.CreateParameter("HighUser",adVarChar,adParamOutput,30)
MyCommand.Parameters.Append.MyFirstParam
Set MySecondParam=MyCommand.CreateParameter("LowUser",adVarChar,adParamOutput,30)
MyCommand.ParaMeters.Append MySecondParam
MyCommand.Execute
%>

The person with the alphabetically Hiighest name is
<%=MyCommand("HighUser")%>

The person with the alphabetically lowest name is
<%=MyCommand("LowUser")%>
<%
MyConn.Close 
%>

这个脚本的结构与上一个非常相似。在这个脚本中,用CreateParameter()方法创建了两个参数对象,两个参数都被定义为VARCHAR型。为了指明它们是输出参数,使用了常量adParamOutput。最后,在CreateParameter()方法中指定了每个参数的最大长度,30。当你建立的参数是变长度数据类型,如VARCHAR型时,你必须指定一个最大长度。

使用输入参数
现在讨论另外一种参数。SQL存储过程可以接收输入参数。输入参数使你能够把数据传递给存储过程。
例如,假设有一个表保存了用户名和密码。假设你想建立一个检查密码的存储过程。使用下面的这个存储过程,你可以检查一个用户是否输入了合法的密码。

CREATE PROCEDURE sp_CheckPass
(@CHKName VARCHAR(30),@CHKPass VARCHAR(30),@ISValid CHAR(4) OUTPUT)
AS
IF EXISTS(SELECT UserName FROM WebUsers
     WHERE UserName=@CHKName AND UserPass=@CHKPass)
  SELECT @ISVaid="Good"
ELSE
  SELECT @ISValid="Bad"

这个存储过程接收两个输入参数。输入参数@CHKaName向存储过程传递一个用户名。@CHKPass向存储过程传递一个密码。如果有用户拥有指定的密码,输出参数将返回“Good",否则,返回“Bad”。
使用输入参数的方法与使用输出参数的方法非常相似。关键的差别是,命令执行前必须给输入参数分配一个值。这里有一个例子:


<%
Set MyConn=Sever.CreateObject("ADODB.Connection")
Set MyCommand=Sever.CreateObject("ADODB.Command")
MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn 
Set MyCommand.ActiveConnection=MyConn
MyCommand.CommandType=adCMdStoredProc
MyCommand.CommandText="sp_CheckPass"
Set MyFirstParam=MyCommand.CreateParameter("UserName",adVarChar,adParamIntput,30)
MyCommand.Parameters.Append.MyFirstParam
Set MySecondParam=MyCommand.CreateParameter("UserPass",adVarChar,adParamInput,30)
MyCommand.ParaMeters.Append MySecondParam
Set MyThirdParam=MyCommand.CreateParameter("RetValue",adChar,adParamOutput,4)
MyCommand.Parameters.Append MyThirdParam
MyCommand("UserName")="Bill Gates"
MyCommand("UserPass")="Billions"
MyCommand.Execute
%>
The password is <%=Mycommand("RetValue")%>
<%
MyConn.Close 
%>
在这个例子中,名字Bill Gates和密码Billions被传递给存储过程。如果表中存在这个名字-密码组合,则报告该密码为Good,否则报告该密码为Bad。
在这个脚本中,用常量adParamInput指定两个输入参数。注意两个输入参数在命令执行前都被分配了一个值。

取出参数信息
你会发现有时你需要用到一个存储过程,但是不知道该存储过程需要什么参数。例如,你也许不知道参数的数据类型或参数的大小。你如何能确定这些信息呢?
用下面的脚本,你可以得到一个存储过程所使用的参数的有关信息:

  
  <%
  Set MyConn=Sever.CreateObject("ADODB.Connection")
  Set MyCommand=Sever.CreateObject("ADODB.Command")
  MyConn.Open "FILEDSN=d:\Program Files\
       Common Files\ODBC\Data Sources\MyData.dsn 
  Set MyCommand.ActiveConnection=MyConn
  MyCommand.CommandType=adCMdStoredProc
  MyCommand.CommandText="sp_myproc"
  MyCommand.Parameters.Refresh
  %>
  
  
  
  

 
  
Parameter Information

  

  <%For Each thing in Mycommand.Parameters %>
  

  <%
  Next
  MyConn.Close
  %>
  


    
Parameter Name
    
Datatype
    
Direction
    
Size
  

  
<%=thing.name%>
  
<%=thing.type%>
  
<%=thing.direction%>
  
<%=thing.size%>
  

  
 

这个例子显示了存储过程sp_myproc的所有参数的有关信息。每个参数的名字,数据类型,说明,和大小被显示在一个表中。(一个参数的说明指明了该参数是输入参数,输出参数,或返回状态值。)要显示另一个存储过程的参数信息,只要替换存储过程名即可。
这个例子中的重要语句是MyCommand.Parameters.Refresh。当这个语句执行时,该存储过程的参数的有关信息被从数据库中取出。
这个脚本不返回常量,它返回的是原始值。要解释这个脚本的返回值,你需要参考包含文件ADODBS。在这个文件中,原始值与正确的常量相对应。

例子应用程序:高级反馈页
在你的站点上包含一个反馈页是个好主意。反馈页使用户能够提出问题,建议,和表示赞扬。你可以利用这些信息来改进你的站点,使它更加符合用户的要求。
建立反馈页的最简单的办法是使用HTML form把反馈信息传送给一个e_mail帐号。例如,下面的HTML页把输入form的信息传送给e_mail帐户webmaster@yoursite.com:
 
 
 
 

please enter any suggestions for improving
this web site in the form below:



 


 
 

对小站点来说,这个反馈form将会工作得很好。所有的反馈信息都被发送到同一个e_mail帐户。但是,如果你站点有多个管理员,你希望所有的管理员都能看到反馈信息。而且,你希望存储反馈信息,以便将来取出这些信息并做分析。在这种情况下,你应该把用户反馈信息存储在数据库的表中。
这一节讲述如何使用ADO来保存和取出用户的反馈信息。你将学习如何建立一个高级反馈form。这个工程中用到了下列表和文件:

■ 表Feedback。SQL Sever数据库的一个表,用来存储用户反馈信息。
■ 反馈网页。一个HTML网页,用户在这个网页中输入反馈信息。
■ 接收网页。一个ASP网页,对用户输入反馈信息表示感谢,把信息存储在数据库中。
■ 显示网页。一个ASP网页,从数据库中取出反馈信息并显示。

创建表Feedback
表Feedback有四个字段,分别用来存储e_mail地址,IP地址,反馈输入的时间,和反馈信息的内容。要创建这个表,从Microsoft SQL Sever程序组中启动ISQL/w。接下来,在查询窗口中输入以下的文本并执行它:

CREATE TABLE Feedback (Feed_Email VARCHAR(50),
            Feed_IP VARCHAR(20),
            Feed_Date DATETIME Default GetDATE()
            Feed_Contents TEXT)

创建反馈网页
反馈网页是一个标准的HTML网页(见图24.1)。它有一个文本框和一个多行文本框,用户可以在文本框中输入他们的e_mail地址,在多行文本框中输入反馈信息。它还有一个用来提交反馈的提交按钮。当提交了反馈后,将显示接收网页。表24.1显示了网页Feedback的脚本。

图24.1
 

表24.1 feedback.htm

Please enter any suggestions for improving this web site in the form below: 

Please enter your email address:

创建接收网页
接收网页有两个作用。首先,它用来对用户提供反馈信息表示感谢(见图24.2)。第二,更重要的是,这个网页用来把反馈信息存储在表Feedback中。反馈信息的添加使用的是SQL INSERT语句,如表24.2所示。
 

图24.2
 

表24.2 acknowledge.asp
<% ' Retrieve form fields into variables Email=Replace(Request.Form("Email"),"'","''") Contents=Replace(Request.Form("Contents"),"'","''") 
' Check for empty content IF Email="" THEN Email="Unknown" IF Contents="" THEN Contents="None" 
' Grab the user's IP address UserIP=Request.ServerVariables("REMOTE_ADDR") 
' Create the SQL command string MySQL="INSERT Feedback (Feed_Email,Feed_IP,Feed_Contents)   VALUES ('"&Email&"','"&UserIP&"','"&Contents&"')" 
' Insert the form data into the Feedback table Set MyConn=Server.CreateObject("ADODB.Connection") MyConn.Open "FILEDSN=d:\Program Files\Common   Files\ODBC\Data Sources\MyData.dsn" MyConn.Execute MySQL %>

Thank you for your suggestions! 

 

 


注意这个脚本中如何使用VBScript函数Replace()。函数Replace()把所有的单引号替换为双引号。这对于防止SQL Sever认为已经到了SQL命令字符串的结尾是有必要的。如果没有使用函数Replace(),一个用户输入了包含单引号的反馈信息时,INSEET语句将会导致错误。

创建显示网页
显示网页用来显示用户输入的反馈信息(见图24.3)。反馈信息取自表Feedback。因为一个站点也许会收到几千个反馈信息,显示网页不显示表中的所有记录,而是只显示最后25个信息。这通过使用记录集对象的Maxrecords属性来实现。
 

图24.3
 

为了显示每个反馈信息的内容,使用了一个多行文本框。使用多行文本框的好处是它们有滚动条。如果有用户输入了相当长的反馈信息,它不会占满整个显示网页。表24.3是display.asp的脚本。

表24.3 display.asp
<% ' Create ADO objects Set MyConn=Server.CreateObject("ADODB.Connection") Set RS=Server.CreateObject("ADODB.RecordSet") MyConn.Open "FILEDSN=d:\Program Files\Common   Files\ODBC\Data Sources\MyData.dsn" 
' Set the maximum number of records to return RS.MaxRecords=25 
' Retrieve the records RS.Open "SELECT * FROM Feedback ORDER BY Feed_Date DESC", MyConn %> 
 

<% ' Display the records WHILE NOT RS.EOF %>
Date Entered: <%=RS("Feed_Date")%>
Email: <%=RS("Feed_Email")%>
IP Address: <%=RS("Feed_IP")%>


<% RS.MoveNext WEND %> 
 

<% ' Close the Recordset and Connection RS.Close MyConn.Close %> 
例子应用程序:创建密码保护系统
这一节演示如何使用ADO对你的站点进行密码保护。你将学习如何创建一个注册网页,新的访问者可以用它注册到你的站点上。你还将学习如何防止访问者看到他们没有访问权限的网页。
为什么需要一个密码保护系统呢?你可以配置IIS,使用基本认证模式或WINDOWS NT Challenge/Response认证模式。使用两种中的任一种认证系统,通过改变对文件的权限,你可以强制用户在访问一个网页之前输入密码。


要了解使用基本认证模式和WINDOWS NT Challenge/Response认证模式的更多内容,请参阅第20章的“使用权限检查组件”一节。

但是,不论使用基本认证模式或WINDOWS NT Challenge/Response认证模式,都存在一个问题。这两种认证系统都是与WINDOWS NT安全体系想分离的。这意味着每当有新用户注册时,你都要手工添加用户。而且你不能容易地从ASP网页中访问和修改密码和用户名。
如果你只是想通过密码来保护你自己的和其他管理员的特殊网页,IIS提供的两种认证系统都是可行的。但是,假如你想在用户提供了诸如电话号码或信用卡号码这样的信息后,自动为新用户进行注册。在这种情况下,你需要建立一个密码确认系统。
在这一节,你将学习如何使用ADO建立一个密码确认系统。你需要建立如下的数据库表和两个文件:

■ 表webusers。用来保存注册信息。
■ 注册网页。这个ASP网页包含一个注册表单。通过完成这个表单,一个新用户可以获得对你站点的访问。
■ 密码包含文件。每一个需要密码保护的网页都要包含这个文件。

创建表webusers
表webusers是一个包含三个字段的SQL Sever表。第一个字段保存用户名,第二个字段保存用户密码,第三个字段保存用户的电话号码。
要创建这个表,从Microsoft SQL Sever程序组中启动ISQL/w。然后,在查询窗口中键入以下的文本并执行它:

CRETAT TABLE webusers (UserName VARCHAR(30),
            UserPass VARCHAR(30),
            UserPhone VARCHAR(30))

无论何时,当一个新访问者试图访问一个密码保护的网页时,将对这个表进行用户名和密码的查询。

创建注册网页
注册网页使新访问者可以注册到你的站点上(见图24.4)。如果某个没有合法密码的访问者试图访问一个密码保护的网页,他(她)将被导向这个注册网页。
 

图24.4
 
 

注册网页用了一个选择结构。如果HTML form中的各个域没有都填入数据,就显示这个网页。否则,如果所有的域都填入了数据,将发生三件事情:

■ 首先,注册信息被插入到表webusers中。
■ 第二,新的用户名和密码被分配给session变量UserName和UserPass。
■ 最后,该用户被导向他原来所在的网页(如果原来的网页是未知的,则被导向主页)。

注册网页只要求用户输入很少的信息。但是,你可以很容易地扩展这个例子,询问用户任何你想知道的信息。例如,你可以要求用户在使用你的站点之前输入一个信用卡号码或地址。要做到这一点,只要在HTML form和表webusers中增加一个域即可。表24.4是注册网页的脚本。


如果你在注册表单中要求输入象信用卡号码这样的重要信息,你应该使用加密管道层(SSL)对信息进行加密。要了解加密管道层的更多信息,请参阅第二章,“安装和使用Internet Information Sever”。

表24.4  register.asp
<% CONST HomePage="/default.asp" 
' Check If Registration Information Is Incomplete IF Request.Form("UserName")="" OR Request.Form("UserPass")="" [ccc]OR Request.Form("UserPhone")="" THEN %> 
       

Please complete all of the following information:

 

">  
  
  
  User Name:  " >   
   Password:           VALUE="<%=Request.FORM("UserPass")%>">   
   Phone Number:    ">   
         
      <% ELSE 
 ' Ready Database Objects  Set MyConn=Server.CreateObject("ADODB.Connection")  MyConn.Open "FILEDSN=d:\Program Files\Common  Files\ODBC\Data Sources\MyData.dsn" 
 ' Insert The Registration Information Into WebUsers  MySQL="INSERT WebUsers (UserName,UserPass,UserPhone) VALUES ("  MySQL=MySQL&"'"&Request.FORM("UserName")&"'"  MySQL=MySQL&",'"&Request.FORM("UserPass")&"'"  MySQL=MySQL&",'"&Request.FORM("UserPhone")&"')"  MyConn.Execute MySQL  MyConn.Close 
 ' Create Session Variables  Session("UserName")=Request.FORM("UserName")  Session("UserPass")=Request.FORM("UserPass") 
 ' Redirect The User To The Appropriate Page  IF Session("GoBack")="" THEN Session("GoBack")=HomePage  Response.Redirect Session("GoBack") END IF %> 
创建密码包含文件
密码包含文件被包含在你想进行密码保护的每一个网页中。它检查session变量UserName和UserPass是否存在。如果不存在,就要求用户输入名字和密码(见图24.5)。然后到表webusers中查询输入的名字和密码。如果密码是非法的,用户将被重新导向注册网页。表24.5是包含文件的脚本。
 

图24.5
 

表24.5 pass.inc
<% IF Session("UserName")="" OR Session("UserPass")="" THEN  IF Request.FORM("UserName")="" OR Request.FORM("UserPass")="" THEN %>

To access this page, you must enter a password: 

If you are a new user, click here. 
</A>" >
NAME
PASSWORD

<% Response.End  ELSE ' Ready Database Objects  Set MyConn=Server.CreateObject("ADODB.Connection")  MyConn.Open "FILEDSN=d:\Program Files\Common [ccc]Files\ODBC\Data Sources\MyData.dsn"  ' Check The Password  MySQL="SELECT UserName FROM WebUsers  WHERE USERNAME='"&Request.FORM("UserName")  MySQL=MySQL&"' AND USERPASS='"&Request.FORM("UserPass")&"'"  SET RS=MyConn.Execute(MySQL) 
 ' If the password is bad, redirect to the Registration Page   IF RS.EOF THEN   RS.CLOSE   Session("GoBack")=Request.ServerVariables("SCRIPT_NAME")   Response.Redirect "register.asp"   Response.END   END IF  RS.CLOSE  END IF END IF %>

测试密码系统
要在你的站点上完成这个密码保护系统,你需要把文件pass.inc包含在每一个要进行密码保护的ASP网页中。(在标准的HTML网页中不能包含这个文件。)表24.6是应该简单的例子。

表24.6 testpass.asp
Only registered users can see this sentence!

这个ASP网页只对已经注册的用户显示。本节中,在测试这个网页时,你可以用Session.Aandon方法删除session变量。session变量UserName和UserPass被删除后,你必须重新输入密码才能访问一个密码保护的网页。

总结
这一章探索了如何使用命令对象执行SQL存储过程。你学习了如何传送和得到输入参数,输出参数,和返回值。本章的第二节提供了使用ADO的两个例子应用程序。你学习了如何创建一个高级反馈网页,如何对站点进行密码保护。
这一章是关于Active Sever Pages对象和组件的最后一章。在本书的下一部分,“使用Microsoft Visual studio”中,你将学习如何使用Visual Studio中的一些程序。这些程序使你能够容易地创建和扩展你的ASP网页。

 
  www.shu1.com  
书艺文学网 书艺文学网:www.shu1.com