一、数据库远程管理技术
基于互联网的广域网现代应用中的一个重要环节是数据库远程监控。首先简单回顾一下互联网上的数据库远程管理技术的发展过程和方式:
早期通过编写CGI-BIN程序模块进行数据库远程管理。但CGI-BIN的运行速度慢,维护很不方便,现在已经基本被弃用。
这几年使用组件对象模型(Component Object Model, COM)的应用非常多,效果也很好。但如果使用的是第三方服务器(笔者的网站就是建立在第三方的虚拟主机上),服务器方往往因为保密或其它商业原因不允许用户注册自己的组件。
近年来由微软公司推出的.NET平台和SUN公司的J2EE平台都是非常高档的数据库远程管理与服务平台。都能提供优质的多层(n-Tier)应用服务。
其中,.NET的简单对象访问协议(Simple Object Access Protocol, SOAP)使用超文本传输协议(Hypertext Transfer Protocol, HTTP)和扩展标记语言(Extensible Markup Language, XML)技术实现跨系统(例如Windows - Linux)的通讯服务方式已经广为开发商接受和使用。许多大型应用,例如企业资源计划(Enterprise resource planning, ERP)等都建立在这样的大型平台之上。
但对于中小型应用,比如一个网站的建设和维护,这种大型应用平台就显得有些尾大不掉,开销也过于庞大。
曾经在互联网技术和Java技术方面一度落后的微软公司在XML应用开发则走在了前头。她的XML解析器(MSXML)中的XMLHTTP协议是一个非常方便实用的客户/服务通讯管道。综合运用XMLHTTP以及ActiveX数据对象(ActiveX Data Objects, ADO/ADOX)可以简单方便地实现数据库远程管理。
本文介绍如何综合运用XMLHTTP和ADO/ADOX进行远程数据库管理。
二、数据库远程管理体系
数据库远程管理的任务流程是:
1、客户端向服务端发出数据库结构和数据的查询或修改指令。
2、服务端接受并执行有关指令并向客户端返回结果。
3、客户端接受并显示服务端返回的指令执行结果。
实现数据库远程管理的二个主要关键环节是:
1、客户端与服务端之间的指令上传和结果下传的数据通道,由XMLHTTP协议实现。
2、服务端前沿与数据库之间的指令传送和结果返回,由起着中间层作用的ADO/ADOX接口完成。
三、XMLHTTP的使用
顾名思义,XMLHTTP是个传送XML格式数据的超文本传输协议。
实际上,XMLHTTP的数据传输过程更为灵活一些:
它上传的指令可以是XML格式数据,也可以是字符串,流,或者一个无符号整数数组。还可以是URL的参数。
它下达的结果可以是XML格式数据,也可以是字符串,流,或者一个无符号整数数组。
详情可参阅文末链接。
客户端调用XMLHTTP的过程很简单,只有5个步骤:
1、创建XMLHTTP对象
2、打开与服务端的连接,同时定义指令发送方式,服务网页(URL)和请求权限等。
客户端通过Open命令打开与服务端的服务网页的连接。与普通HTTP指令传送一样,可以用"GET"方法或"POST"方法指向服务端的服务网页。
3、发送指令。
4、等待并接收服务端返回的处理结果。
5、释放XMLHTTP对象
XMLHTTP方法:
Open bstrMethod, bstrUrl, varAsync, bstrUser, bstrPassword
bstrMethod:数据传送方式,即GET或POST。
bstrUrl:服务网页的URL。
varAsync:是否异步执行。缺省为True,即异步执行,但只能在DOM中实施异步执行。 应用中一般将其置为False,即同步执行。
bstrUser:用户名,可省略。
bstrPassword:用户口令,可省略。
Send varBody
varBody:指令集。可以是XML格式数据,也可以是字符串,流,或者一个无符号整数数组。也可以省略,让指令通过Open方法的URL参数代入。
setRequestHeader bstrHeader, bstrValue
bstrHeader:HTTP 头(header)
bstrValue:HTTP 头(header)的值
如果Open方法定义为POST,可以定义表单方式上传:
xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
另外的一些方法:
abort
取消当前 HTTP 请求
getAllResponseHeaders
从响应信息中检索所有的标头字段
getResponseHeader
从响应信息正文中获得一个 HTTP 标头值
XMLHTTP属性:
onreadystatechange:在同步执行方式下获得返回结果的事件句柄。只能在DOM中调用。
readyState Long 异步操作的状态:未初始化(0),正在加载(1),已加载(2),交互(3),已完成(4)
responseBody:Variant 结果返回为无符号整数数组。
responseStream:Variant 结果返回为IStream流。
responseText :string 结果返回为字符串。
responseXML: object结果返回为XML格式数据。
status Long 服务器返回的HTTP状态码
statusText String 服务器HTTP响应行状态
下面是本文附件源程序中的一个应用示例:
Function GetResult(urlStr)
Dim xmlHttp
Dim retStr
Set xmlHttp = CreateObject("Msxml2.XMLHTTP") '创建对象
On Error Resume Next '出错处理
xmlHttp.Open "POST", urlStr, False '用POST方式打开连接,异步执行。
xmlHttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" '上传表单
xmlHttp.Send '发送指令
If Err.Number = 0 Then '如果连接正确
retStr = xmlHttp.responseText '等待并获得服务端返回的结果字符串
Else
retStr = "Url not found" '否则返回出错信息
End If
Set xmlHttp = nothing '释放对象
GetResult = retStr '返回结果
End Function
GetResult()函数带入一个服务网页的URL参数,把上传的指令安放在URL后面的参数上,如:
urlStr = "server.asp?cmd=" & cmd & "&db=" & db & "table=" & table
cmd:执行方式,例如查询,修改,删除等等。
db:服务端数据库名
table:服务端表名
然后提交指令,等待并接收返回的处理结果。结果以字符串方式返回。
最后由函数调用者处理并显示结果。
使用何种数据类型?
正如上面所说,通过 XMLHTTP 通道传送的数据可以有很多种类型。其中用的最多的是 XML DOM 和 STRING。
选用何种数据类型取决于程序的需要。
为了从服务器取得数据,客户端和服务器都使用 XML 数据是一个很好的方法。因为这样可以处理大量的数据,请求服务器添加/删除/修改/查询 记录,或在客户端排序/过滤数据。
本文的目的是为了在虚拟主机上远程管理数据库,所以这需要有如下两个功能:
1. 远程管理数据库:添加/删除/修改/查询 远程数据库/表/字段。
2. 远程管理数据库中的数据: 添加/删除/修改/查询 记录
所以这里我们使用 XMLHTTP 来发送/接受 字符串
这样做的好处很明显:可以无闪烁刷新页面
由于是采用字符串, 所以可以简单的使用 "Response.Write" 来返回结果。一旦服务器 response 完毕,客户端用 "xmlHttp.responseText" 方法来获取整个结果,并返回给调用者,用于刷新页面数据。
如果采用异步方式,则客户端按下按钮后,会有一定的延时,客户端必须等待返回数据。如果采用异步或使用 XML DOM 则可以避免这一点。
Using ADOX
ADO 不能用来远程管理数据库,我们可以使用 ADOX。
ADOX 是 ADO 的扩展, 它提供了更多的函数用于处理数据库。一旦通过身份认证,并且你的角色为数据库管理员,那么你可以通过 ADOX 作任何操作。
This sample requests:
生成动态的 select 菜单,显示指定路径下的数据库名。
生成动态的 select 菜单,显示上述菜单中选定的数据库中的表名。
根据选定的数据库和表,动态的列出字段名。
根据虚拟目录路径的改变和 select 的改变,即时的改变显示的内容而且无闪烁的刷新页面。
使用 Scripting.FileSystemObject 获得给定路径的数据库名。 使用 ADOX 获取表名和字段名。代码如下:
获取一个数据库中的表名:
Sub GetTables_Server(DBName)
Dim i
Dim catDB ’ADODB.Catalog 对象
Set catDB = Server.CreateObject("ADOX.Catalog") ’创建 ADODB.Catalog 对象
On Error Resume Next ’错误处理
catDB.ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Server.MapPath(DBName) ’打开连接
’如果需要可加上用户名和密码
If Err.Number = 0 Then ’成功
’ 动态产生 select 选单
Response.Write "<select name=’selTable’ onChange=ShowResult(’fields’)>"
With catDB
For i = 0 To .Tables.Count -1
If .Tables(i).Type = "TABLE" then ’ 如果是一个表
’将表名添加到 select
Response.Write "<option value=" & .Tables(i).Name & ">" &_
.Tables(i).Name &"</option>"
End If
Next
End With
Response.Write "</select>" ’ select 输出完毕
Else
’错误信息
Response.Write "错误: 不能打开数据库 - " & DBName
End If
Set catDB = Nothing ’ 释放 ADODB.catalog 对象
End Sub
获取表中的字段名:
Sub GetFields_Server(dbName, tableName)
Dim i, j
Dim catDB ’ADODB.Catalog 对象
Set catDB = Server.CreateObject("ADOX.Catalog") ’创建 ADODB.catalog 对象
On Error Resume Next ’错误处理
catDB.ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Server.MapPath(dbName) ’打开连接
’如有必要在此添加用户名和密码
If Err.Number = 0 Then ’ 成功
’找到匹配的表名
With catDB
For j = 0 To .Tables.Count -1
If (.Tables(j).Type = "TABLE") and (.Tables(j).Name = tableName) Then
Exit For
End If
Next
End With
’列出字段名
With catDB.Tables(j)
For i = 0 To .Columns.Count -1
’如果是主键,选中之
If .Columns(i).Properties("Autoincrement") = True Then
Response.Write "<input type=’radio’ name=’field’ value=" &_
.Columns(i).Name & " checked=true>" & .Columns(i).Name & ""
’显示字段名
Else
Response.Write "<input type=’radio’ name=’field’ value=" &_
.Columns(i).Name & ">" & .Columns(i).Name & ""
’显示字段名
End If
Next
End With
Else
’Error message
Response.Write "错误: 不能打开数据库 - " & dbName
End If
Set catDB = Nothing ’ 释放 ADODB.catalog 对象
End Sub
注:本例中所有的表采用了自增字段作为主键。如果你的数据库中未采用自增字段作为主键或未指定主键,则需要重写上述代码。使用自增字段作为主键是一个很好的习惯。
补充资料:js版本
MSXML中提供了Microsoft.XMLHTTP对象,能够完成从数据包到Request对象的转换以及发送任务。
创建XMLHTTP对象的语句如下:
Set objXML = CreateObject("Msxml2.XMLHTTP") 或
Set objXML = CreateObject(“Microsoft.XMLHTTP”)
’ Or, for version 3.0 of XMLHTTP, use:
’ Set xml = Server.CreateObject("MSXML2.ServerXMLHTTP")
对象创建后调用Open方法对Request对象进行初始化,语法格式为:
poster.open http-method, url, async, userID, password
Open方法中包含了5个参数,前三个是必要的,后两个是可选的(在服务器需要进行身份验证时提供)。参数的含义如下所示:
http-method: HTTP的通信方式,比如GET或是 POST
url: 接收XML数据的服务器的URL地址。通常在URL中要指明 ASP或CGI程序
async: 一个布尔标识,说明请求是否为异步的。如果是异步通信方式(true),客户机就不等待服务器的响应;如果是同步方式(false),客户机就要等到服务器返回消息后才去执行其他操作
userID 用户ID,用于服务器身份验证
password 用户密码,用于服务器身份验证
XMLHTTP对象的Send方法
用Open方法对Request对象进行初始化后,调用Send方法发送XML数据:
poster.send XML-data
Send方法的参数类型是Variant,可以是字符串、DOM树或任意数据流。发送数据的方式分为同步和异步两种。在异步方式下,数据包一旦发送完毕,就结束Send进程,客户机执行其他的操作;而在同步方式下,客户机要等到服务器返回确认消息后才结束Send进程。
XMLHTTP对象中的readyState属性能够反映出服务器在处理请求时的进展状况。客户机的程序可以根据这个状态信息设置相应的事件处理方法。属性值及其含义如下表所示:
值 说明
0 Response对象已经创建,但XML文档上载过程尚未结束
1 XML文档已经装载完毕
2 XML文档已经装载完毕,正在处理中
3 部分XML文档已经解析
4 文档已经解析完毕,客户端可以接受返回消息
客户机处理响应信息
客户机接收到返回消息后,进行简单的处理,基本上就完成了C/S之间的一个交互周期。客户机接收响应是通过XMLHTTP对象的属性实现的:
● responseTxt:将返回消息作为文本字符串;
● responseXML:将返回消息视为XML文档,在服务器响应消息中含有XML数据时使用;
● responseStream:将返回消息视为Stream对象
------就是下面这个很简单的JAVASCRIPT函数SEND(STR,URL)---------------
使用到的是XMLDOM和XMLHTTP对象.用这种技术的好处是:全JS控制,方便/简单,比RDS
或者remote好多了.(前提:服务器端和客户端都必须安装IE5或者更高版本),在俺贴的
那个无刷新在线信息功能使用的也是这种技术.有兴趣的朋友可以看看..
function Send(Str,URL)
//STR参数是传入的XML数据,你也可以传入其他文本数据.
//不过这个函数需要服务器端处理之后返回XML数据,你也可以修改一下
//URL参数表示你所要处理数据的ASP文件地址
{
var Http = new ActiveXObject("Microsoft.XMLHTTP") //建立XMLHTTP对象
var Dom = new ActiveXObject("Microsoft.XMLDOM") //建立XMLDOM对象
Http.open("POST",URL,false)
//第一个参数的意思是,用"POST"方式发送数据.可以大到4MB,也可以换为"GET".只能256KB
//第2个参数的意思是数据发送到哪个文件处理
//第3个参数意思是同步或异步方式.TRUE为异步,FALSE为同步
Http.send(Str) //开始发送数据.............嘟嘟..
Dom.async=false //设置为同步方式获取数据
Dom.loadXML(Http.responseText)
//开始获取服务器端处理后返回的数据.我在这里设置必须为XML数据,否则出错.
//你也可以自己修改.使返回的是2进制或者记录集数据.................................
if(Dom.parseError.errorCode != 0) //检查是否发生获取数据时错误
{
delete(Http)
delete(Dom)
return(false)
}
else
{
var Back = Dom.documentElement.childNodes.item(0).text
//得到返回的XML数据,我这里假设处理程序只返回一行XML数据(一个节点)
delete(Http)
delete(Dom)
return(Back) //函数返回数据.......................结束
}
}
VAR CAT = Send("<用户资料><姓名>谢柠檬</姓名></用户资料>","HTTP://WWW.CHINAASP.COM/VIVA.ASP") //执行函数
IF(CAT == FALSE)
{
ALERT("对不起.处理程序返回的是FALSE.数据处理已经失败........")
}
ELSE
{
IF(EVAL(CAT))
{
ALERT("OK.数据已经发送成功.兼以处理完成!!!!!!")
}
ELSE
{
ALERT("对不起.处理程序返回的是FALSE.数据处理已经失败........")
}
}
===============================VIVA.ASP============================
ON ERROR RESUME NEXT
DIM BOBO
DIM MOMO
SET BOBO = SERVER.CREATEOBJECT("MICROSOFT.XMLDOM")
BOBO.ASYNC = FALSE
BOBO.LOAD REQUEST
IF BOBO.PARSEERROR.ERRORCODE <> 0 THEN
RESPONSE.WRITE("<程序处理结果><最终结果>FALSE</最终结果></程序处理结果>")
ELSE
SET MOMO = BOBO.DOCUMENTELEMENT
IF MOMO.CHILDNODES.ITEM(0).TEXT = "谢柠檬" THEN
RESPONSE.WRITE("<程序处理结果><最终结果>TRUE</最终结果></程序处理结果>")
ELSE
RESPONSE.WRITE("<程序处理结果><最终结果>FALSE</最终结果></程序处理结果>")
END IF
END IF
SET BOBO = NOTHING
下面是个实际应用的例子
<%
Dim objXMLHTTP, xml
Set xml = Server.CreateObject("Microsoft.XMLHTTP") ’创建对象
xml.Open "GET","http://www.pconline.com.cn/pcedu/empolder/wz/xml/0404/366680.html",False ’ ’设置对象,具体xmlhttp详细使用方法请见:http://www.cnsxml.com/blogview.asp?logID=273 ; 《XMLHTTP 对象及其方法》一文
xml.Send ’发送请求
Response.AddHeader "Content-Disposition", "attachment;filename=mitchell-pres.zip" ’添加头给这个文件
Response.ContentType = "application/zip" ’设置输出类型
Response.BinaryWrite xml.responseBody ’输出二进制到浏览器
response.
Set xml = Nothing
%>
XMLHttpRequest的同步和异步请求
客户端利用XMLHTTP发送请求得到服务端应答数据,并用Javascript操作DOM最终更新页面- 又称无刷新更新页面,有代替传统web开发中采用form(表单)递交方式更新web页面的趋势。
XMLHTTP依赖于XMLHttpRequest完成从客户端的请求到服务端的应答。XMLHttpRequest提供了两个方法open和send。open方法用于初始化XMLHttpRequest
对象、指示请求的方式(get、post等)、安全性连接等,在调用open方法后必须调用send方法发送Http Request(Http请求)以返回Http Reponse(Http应答)。
看MSDN中对send方法的简介:
This method is synchronous or asynchronous, depending on the value of the bAsync parameter in the open call. If open is called with bAsync == False, this call does not return until the entire response is received or the protocol stack times out. If open is called with bAsync == True, this call returns immediately.
send方法是否同步或异步工作取决于open方法中的bAsync参数,如果bAsync == False表示send方法工作在同步状态下,发送http请求后,只有当客户端接收到来自服务端的全部应答数据或协议栈超时返回!反之bAsync == True,工作在异步状态下,直接返回。
实际运用中,设置bAsync = True, 使send方法被调用后XMLHttpRequest工作在异步状态,如果设为同步状态可能会导致不必要的长时间等待!
另外,无论在同步或异步请求工作状态下,XMLHttpRequest如何得到由服务端返回的应答数据?
看下面的示例代码:
<script>
var xmlhttp=null;
function PostOrder(xmldoc)
{
varxmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
xmlhttp.Open("POST", "http://myserver/orders/processorder.asp", false);
xmlhttp.onreadystatechange= HandleStateChange;
xmlhttp.Send(xmldoc);
}
function HandleStateChange()
{
if (xmlhttp.readyState == 4)
{
alert("Result = " + xmlhttp.responseXML.xml);
}
}
</script>
服务端返回应答数据并完全被加载, 可通过XMLHttpRequest属性readState获知,其值变为4 - COMPLETED (已加载完成),
当readState变化时会调用XMLHttpRequest对象中的回调函数onreadstatechange,在函数中验证xmlhttp.readyState == 4,
这里得到的是XML文档(如果服务端有返回xml文档数据).
通过xmlHttp和ASP的结合,我们可以轻松完成网页的异步调用。
代码如下:
1.新建Display.asp(这是前台显示页面)
注意xmlhttp.readyState的4个属性
1:LOADING;2:LOADED;3:INTERACTIVE;4:COMPLETED
<%@ Language=VBScript %>
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
</HEAD>
<script language="javascript">
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
function fnDo(ID)
{
var xmlDom = new ActiveXObject("Msxml2.DOMDocument");
var strURL = "GetInfo.asp?ID=" + ID;
xmlhttp.Open("POST",strURL , true);
xmlhttp.onreadystatechange = fnRun;
xmlhttp.Send(xmlDom);
divTest.innerHTML = "Loading..."
}
//--------------------------------------------------------
function fnRun()
{
var state = xmlhttp.readyState;
var xmlDom = new ActiveXObject("Msxml2.DOMDocument");
if (state == 4)
{
xmlDom.loadXML(xmlhttp.responseXML.xml);
//alert(xmlDom.documentElement.selectSingleNode("//objXML").text)
var getInfo = xmlDom.documentElement.selectSingleNode("//objXML").text;
divTest.innerHTML = getInfo
}
}
</script>
<BODY>
<input type=button value="异步调用" οnclick="fnDo(document.all.txtInput.value)">
<input type=text id=txtInput>
<DIV id=divTest></DIV>
<P> </P>
</BODY>
</HTML>
2.在建立GetInfo.asp(这是后台处理页面)
<%
Dim sID,objResult
sID = Trim(Request("ID"))
’sID = 28
Set objResult = Server.CreateObject("MSXML2.DOMDocument")
objResult.loadXML ("<objXML></objXML>")
’**************************************************************
’**************************************************************
objResult.selectSingleNode("objXML").text = "Get:" & sID
Response.ContentType = "text/xml"
objResult.save (Response)
Response.End
Set objSch = Nothing
Set objResult = Nothing
%>
3.运行Display.asp页面,在文本框里输入内容,点击按钮,可以看到Loading的提示,随后在不刷新页面的情况下得到了文本框里的内容。当然你也可以在GetInfo.asp那个页面里根据发送的参数做一些复杂的出来,随后把结果返回出来。
XmlHttp异步获取网站数据的例子(孟子E章)
文档提供者:newebug () 于 2005-3-15
<script>
var oDiv
var xh
function getXML()
{
oDiv = document.all.m
oDiv.innerHTML = "正在装载栏目数据,请稍侯......."
oDiv.style.display= ""
xh = new ActiveXObject("Microsoft.XMLHTTP")
xh.onreadystatechange = getReady
xh.open("GET",a.value,true)
xh.send()
}
function getReady()
{
if(xh.readyState==4)
{
if(xh.status==200)
{
oDiv.innerHTML = "完成"
}
else
{
oDiv.innerHTML = "抱歉,装载数据失败。原因:" + xh.statusText
}
}
}
</script>
<body>
xmlhttp异步的例子:
URL:<input name=a value="http://www.microsoft.com" style="width:600px">
<input οnclick="getXML()" type="button" value="得到源代码">
<input οnclick="if(xh && xh.responseText) {alert(xh.responseText);oDiv.innerHTML=xh.responseText}" type="button" value="显示源代码">
<div id=m></div>