H
hfghfghfg
Unregistered / Unconfirmed
GUEST, unregistred user!
将一个局域网的AD0的mis程序升级到互联网的方法:
1。直接用tcpip:1433连接。“ 路由后的内网”,“代理” 好像有些问题?
ok,俺用VNN,或者VPN。虽然有点不顾江湖道义。但也是一种方法。
这一招的名称叫做:“它山之石”
2。TWebConnection/TSocketConnection。改起来也快。偷懒的人可以
如下处理:DataSetProvider使用[poAllowCommandText],然后写一
个工具,替换修改*.pas,*.dfm的代码(控件名字无需改,只改定义
,然后就是
SQL.Clear > CommandText:=''
SQL.Text:='???????' > CommandText:= '???????'
SQL.Add('????') > CommandText:=CommandText+'????'#13#10
)。几百窗体的普通程序也用不了一两天。
这一招的名称叫做:“见山不是山,见水不是水”,看上去是个
ADOQuery(名字:“ADOQry_select”),其实是个ClientDataSet。(这是
同事说的)
ps:改之前要备份好。改完了顺道改了delphi自带的
httpsrvr 或者scktsrvr (个人建议)。
3。使用ADO2.5以后的新特性(流支持 见附录),改了ADODB.pas。
例如
在TADOConnection加
public
Httphost: string;
HttpConnected: boolean;
我用了HTTP,其实也可用udp,tcpip等等,你要不嫌慢用串口也行。
另外写了几个函数(见附录)。我把改了的ADODB.pas复制的我的程序
目录里,加了一句
ADOConnection1.Httphost := 'http://220.203.0.??/svr/sql.dll/sql';
编译一下,运行,俺的程序就 晃晃悠悠的运行在web服务器的数据库下
了。另外我做了与TWebConnection/TSocketConnection的性能比较测试。
每次查询top 1 条记录(每个表查一次,循环10次)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 0.723 1.781
每次查询top 60 条记录
(每个表查一次,循环10次 有的表没有记录 或只有几条记录,80%的表还
是有不少记录的)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 1.917 2.792
每次查询top 400 条记录
(每个表查一次,循环10次 有的表没有记录 或只有几条记录,80%的表还
是有不少记录的)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 5.113 3.846
SocketConnection在查询记录多时,有时停很久。
我在数据传输时用了zlib压缩。
另外delphi 通过
Import Type Library 导入
C:/Program Files/Common Files/System/ado.msado26.tlb
生成的声明最好不要用。
俺之所以这样用的 原因:
1。以前的程序可以轻松的使用互联网的数据库
只需根据设置决定是否执行
ADOConn.Httphost := 'http://220.203.0.??/svr/sql.dll/sql';
2。WebConnection速度慢,SocketConnection大数据量下也不好。
3。这样改的程序可以可以通过设置在局域网中依然用原来的
模式(速度快)。例如
if DebugHook=0 then
ADOConn.Httphost := 'http://220.203.0.??/logserver/sql.dll/sql'
else
....................
这样可以在delphi 调试时连本地库(速度快 呵呵)。
一句话,就是灵活了。
缺点:
事务 与WebConnection 一样,自己处理。
其实 这种方法是邪派的,不过我经常遇到一些问题,时间紧,就只好用邪派的招数了。
以前要一天内将一个access的程序(我记得好像是121个窗体)改到sql server上,同时
access的版本也要一直继续下去,因为客户的环境不一样。当时我也是改了ADODB.pas,
主要是加了一个sql转换的环节,即将access的某些函数转为sql server 的,如:
trim() > ltrim(rtrim()) instr > charindex 等 另外配合一些sql server 自定义
的函数 。
正统的做法,改成b/s的吧。因为如果使用web的数据,整体的设计思路不一样,例如,如
果要用WebConnection 你要注意连接的次数,事物处理,脱机时的处理。注意这是正统,
不是正确,正确的方法要视情况定,时间,人手,性能要求,后续发展。。。。。。。。。。。
http://220.203.0.??/svr/sql.dll
是自己随手写的(delphi),你用asp写也可以(附录ADO的例子)。
这一招的名称叫做:“暗渡陈仓”
qq: 105204912 鸽子(花间一壶酒,手上两猪蹄。程序员嘛,自然要多啃猪蹄啦。俗话
说的好,以形补形,俺可是耍手指头的,多啃几只 加 功力 啊。有蹄又岂能无酒,
所谓 酒入肥肠,化作字千行。)
元旦过后 我就改用 Dot Net 了。以后灌水就少了。
下一个灌水的 题目 是 本地数据库 与 网络数据库 的 同步。
前一段时间 我用C#写了一个socket 的信息服务,感觉C#的
线程很特别,有朋友也是用C#的多多交流。
附录
ADO 程序员参考
流和持久性
Recordset 对象的 Save 方法将 Recordset 保存或者持久保留到文件中,
而 Open 方法则从该文件中恢复 Recordset。
现在,Save 和 Open 方法也可以将 Recordset 持久保留到 Stream 对象中。
此功能尤其有助于使用远程数据服务 (RDS) 和 Active Server Pages (ASP)。
方案 4:
在本方案中,ASP 代码将 Recordset 的内容以 ADTG 格式写入客户端。Cursor Service 可以用此数据创建断开连接的 Recordset。
RDS DataControl 的新属性 URL 指向生成 Recordset 的 .asp 页。这意味着获取 Recordset 对象不需要 RDS 使用服务器端 DataFactory 对象,也不需要用户编写业务对象。因此大大简化了 RDS 编程模型。
名为 http://server/directory/recordset.asp 的服务器端代码如下:
<%
Dim rs
Set rs = Server.CreateObject("ADODB.Recordset"
rs.Open "select au_fname, au_lname, phone from Authors", "dsn=Pubs"
response.ContentType = "multipart/mixed"
rs.Save response, adPersistADTG
%>
客户端代码:
<HTML>
<HEAD>
<TITLE>RDS Query Page</TITLE>
</HEAD>
<body>
<CENTER>
<H1>Remote Data Service 2.5</H1>
<TABLE DATASRC="#DC1">
<TR>
<TD><SPAN DATAFLD="au_fname"></SPAN></TD>
<TD><SPAN DATAFLD="au_lname"></SPAN></TD>
<TD><SPAN DATAFLD="phone"></SPAN></TD>
</TR>
</TABLE>
<BR>
<OBJECT classid="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
ID=DC1 HEIGHT=1 WIDTH = 1>
<PARAM NAME="URL" VALUE="http://server/directory/recordset.asp">
</OBJECT>
</SCRIPT>
</BODY>
</HTML>
开发人员还可以选择在客户端使用 Recordset 对象。
...
function GetRs()
{
rs = CreateObject("ADODB.Recordset"
rs.Open "http://server/directory/recordset.asp"
DC1.SourceRecordset = rs;
}
...
增加的函数
procedure makeUpstream(s: TMemoryStream; action, sql, memo1, memo2: string);
procedure getRS_stream(ms_Down: TMemoryStream; var errmsg: string; ms_rs: TMemoryStream);
function HttpPutStram(url: string; s_up, s_down: TMemoryStream): Boolean;
function RecordsetFromMS(Stream: TMemoryStream): _Recordset;
function RecordsetFromHttp(Host, sql: string): _Recordset;
function ExecFromHttp(Host, sql: string; NoRecords: boolean; var c: integer): _Recordset;
function HttpConnect(host: string): boolean;
function Http_GetFieldNames(host, tb: string; ss: TStrings): boolean;
function Http_GetTableNames(host: string; sys: boolean; ss: TStrings): boolean;
function GetSql(Text: string; p: TParameters): string;
修改
procedure TADOConnection.DoConnect;
begin
if trim(Httphost) <> '' then
begin
HttpConnected := HttpConnect(Httphost);
procedure TADOConnection.DoDisconnect;
begin
if trim(Httphost) <> '' then
begin
HttpConnected := false;
end
procedure TADOConnection.Execute(const CommandText: WideString;
var RecordsAffected: Integer; const ExecuteOptions: TExecuteOptions = [eoExecuteNoRecords]);
var
VarRecsAffected: OleVariant;
begin
if trim(Httphost) <> '' then
begin
ExecFromHttp(trim(Httphost), CommandText, true, RecordsAffected);
function TADOConnection.Execute(const CommandText: WideString;
const CommandType: TCommandType = cmdText;
const ExecuteOptions: TExecuteOptions = []): _Recordset;
var
VarRecsAffected: OleVariant;
i: integer;
begin
if trim(Httphost) <> '' then
begin
Result := ExecFromHttp(trim(Httphost), CommandText, false, i);
procedure TADOConnection.Open(const UserID, Password: WideString);
begin
if trim(Httphost) <> '' then
begin
procedure TADOConnection.GetFieldNames(const TableName: string;
List: TStrings);
const
COLUMN_NAME = 'COLUMN_NAME'; { Do not localize }
var
Fields: _Recordset;
begin
if trim(Httphost) <> '' then
begin
Http_GetFieldNames(Httphost, TableName, list);
procedure TADOConnection.GetTableNames(List: TStrings;
SystemTables: Boolean);
var
TypeField,
NameField: TField;
TableType: string;
DataSet: TADODataSet;
begin
if trim(Httphost) <> '' then
begin
Http_GetTableNames(Httphost, SystemTables, List);
function TADOConnection.GetConnected: Boolean;
begin
if trim(Httphost) <> '' then
begin
Result := HttpConnected;
function TParameters.InternalRefresh: Boolean;
procedure TADOCommand.OpenConnection;
function TADOCommand.Execute(var RecordsAffected: Integer;
const Parameters: OleVariant): _Recordset;
procedure TCustomADODataSet.OpenCursor(InfoQuery: Boolean);
1。直接用tcpip:1433连接。“ 路由后的内网”,“代理” 好像有些问题?
ok,俺用VNN,或者VPN。虽然有点不顾江湖道义。但也是一种方法。
这一招的名称叫做:“它山之石”
2。TWebConnection/TSocketConnection。改起来也快。偷懒的人可以
如下处理:DataSetProvider使用[poAllowCommandText],然后写一
个工具,替换修改*.pas,*.dfm的代码(控件名字无需改,只改定义
,然后就是
SQL.Clear > CommandText:=''
SQL.Text:='???????' > CommandText:= '???????'
SQL.Add('????') > CommandText:=CommandText+'????'#13#10
)。几百窗体的普通程序也用不了一两天。
这一招的名称叫做:“见山不是山,见水不是水”,看上去是个
ADOQuery(名字:“ADOQry_select”),其实是个ClientDataSet。(这是
同事说的)
ps:改之前要备份好。改完了顺道改了delphi自带的
httpsrvr 或者scktsrvr (个人建议)。
3。使用ADO2.5以后的新特性(流支持 见附录),改了ADODB.pas。
例如
在TADOConnection加
public
Httphost: string;
HttpConnected: boolean;
我用了HTTP,其实也可用udp,tcpip等等,你要不嫌慢用串口也行。
另外写了几个函数(见附录)。我把改了的ADODB.pas复制的我的程序
目录里,加了一句
ADOConnection1.Httphost := 'http://220.203.0.??/svr/sql.dll/sql';
编译一下,运行,俺的程序就 晃晃悠悠的运行在web服务器的数据库下
了。另外我做了与TWebConnection/TSocketConnection的性能比较测试。
每次查询top 1 条记录(每个表查一次,循环10次)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 0.723 1.781
每次查询top 60 条记录
(每个表查一次,循环10次 有的表没有记录 或只有几条记录,80%的表还
是有不少记录的)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 1.917 2.792
每次查询top 400 条记录
(每个表查一次,循环10次 有的表没有记录 或只有几条记录,80%的表还
是有不少记录的)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 5.113 3.846
SocketConnection在查询记录多时,有时停很久。
我在数据传输时用了zlib压缩。
另外delphi 通过
Import Type Library 导入
C:/Program Files/Common Files/System/ado.msado26.tlb
生成的声明最好不要用。
俺之所以这样用的 原因:
1。以前的程序可以轻松的使用互联网的数据库
只需根据设置决定是否执行
ADOConn.Httphost := 'http://220.203.0.??/svr/sql.dll/sql';
2。WebConnection速度慢,SocketConnection大数据量下也不好。
3。这样改的程序可以可以通过设置在局域网中依然用原来的
模式(速度快)。例如
if DebugHook=0 then
ADOConn.Httphost := 'http://220.203.0.??/logserver/sql.dll/sql'
else
....................
这样可以在delphi 调试时连本地库(速度快 呵呵)。
一句话,就是灵活了。
缺点:
事务 与WebConnection 一样,自己处理。
其实 这种方法是邪派的,不过我经常遇到一些问题,时间紧,就只好用邪派的招数了。
以前要一天内将一个access的程序(我记得好像是121个窗体)改到sql server上,同时
access的版本也要一直继续下去,因为客户的环境不一样。当时我也是改了ADODB.pas,
主要是加了一个sql转换的环节,即将access的某些函数转为sql server 的,如:
trim() > ltrim(rtrim()) instr > charindex 等 另外配合一些sql server 自定义
的函数 。
正统的做法,改成b/s的吧。因为如果使用web的数据,整体的设计思路不一样,例如,如
果要用WebConnection 你要注意连接的次数,事物处理,脱机时的处理。注意这是正统,
不是正确,正确的方法要视情况定,时间,人手,性能要求,后续发展。。。。。。。。。。。
http://220.203.0.??/svr/sql.dll
是自己随手写的(delphi),你用asp写也可以(附录ADO的例子)。
这一招的名称叫做:“暗渡陈仓”
qq: 105204912 鸽子(花间一壶酒,手上两猪蹄。程序员嘛,自然要多啃猪蹄啦。俗话
说的好,以形补形,俺可是耍手指头的,多啃几只 加 功力 啊。有蹄又岂能无酒,
所谓 酒入肥肠,化作字千行。)
元旦过后 我就改用 Dot Net 了。以后灌水就少了。
下一个灌水的 题目 是 本地数据库 与 网络数据库 的 同步。
前一段时间 我用C#写了一个socket 的信息服务,感觉C#的
线程很特别,有朋友也是用C#的多多交流。
附录
ADO 程序员参考
流和持久性
Recordset 对象的 Save 方法将 Recordset 保存或者持久保留到文件中,
而 Open 方法则从该文件中恢复 Recordset。
现在,Save 和 Open 方法也可以将 Recordset 持久保留到 Stream 对象中。
此功能尤其有助于使用远程数据服务 (RDS) 和 Active Server Pages (ASP)。
方案 4:
在本方案中,ASP 代码将 Recordset 的内容以 ADTG 格式写入客户端。Cursor Service 可以用此数据创建断开连接的 Recordset。
RDS DataControl 的新属性 URL 指向生成 Recordset 的 .asp 页。这意味着获取 Recordset 对象不需要 RDS 使用服务器端 DataFactory 对象,也不需要用户编写业务对象。因此大大简化了 RDS 编程模型。
名为 http://server/directory/recordset.asp 的服务器端代码如下:
<%
Dim rs
Set rs = Server.CreateObject("ADODB.Recordset"
rs.Open "select au_fname, au_lname, phone from Authors", "dsn=Pubs"
response.ContentType = "multipart/mixed"
rs.Save response, adPersistADTG
%>
客户端代码:
<HTML>
<HEAD>
<TITLE>RDS Query Page</TITLE>
</HEAD>
<body>
<CENTER>
<H1>Remote Data Service 2.5</H1>
<TABLE DATASRC="#DC1">
<TR>
<TD><SPAN DATAFLD="au_fname"></SPAN></TD>
<TD><SPAN DATAFLD="au_lname"></SPAN></TD>
<TD><SPAN DATAFLD="phone"></SPAN></TD>
</TR>
</TABLE>
<BR>
<OBJECT classid="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
ID=DC1 HEIGHT=1 WIDTH = 1>
<PARAM NAME="URL" VALUE="http://server/directory/recordset.asp">
</OBJECT>
</SCRIPT>
</BODY>
</HTML>
开发人员还可以选择在客户端使用 Recordset 对象。
...
function GetRs()
{
rs = CreateObject("ADODB.Recordset"
rs.Open "http://server/directory/recordset.asp"
DC1.SourceRecordset = rs;
}
...
增加的函数
procedure makeUpstream(s: TMemoryStream; action, sql, memo1, memo2: string);
procedure getRS_stream(ms_Down: TMemoryStream; var errmsg: string; ms_rs: TMemoryStream);
function HttpPutStram(url: string; s_up, s_down: TMemoryStream): Boolean;
function RecordsetFromMS(Stream: TMemoryStream): _Recordset;
function RecordsetFromHttp(Host, sql: string): _Recordset;
function ExecFromHttp(Host, sql: string; NoRecords: boolean; var c: integer): _Recordset;
function HttpConnect(host: string): boolean;
function Http_GetFieldNames(host, tb: string; ss: TStrings): boolean;
function Http_GetTableNames(host: string; sys: boolean; ss: TStrings): boolean;
function GetSql(Text: string; p: TParameters): string;
修改
procedure TADOConnection.DoConnect;
begin
if trim(Httphost) <> '' then
begin
HttpConnected := HttpConnect(Httphost);
procedure TADOConnection.DoDisconnect;
begin
if trim(Httphost) <> '' then
begin
HttpConnected := false;
end
procedure TADOConnection.Execute(const CommandText: WideString;
var RecordsAffected: Integer; const ExecuteOptions: TExecuteOptions = [eoExecuteNoRecords]);
var
VarRecsAffected: OleVariant;
begin
if trim(Httphost) <> '' then
begin
ExecFromHttp(trim(Httphost), CommandText, true, RecordsAffected);
function TADOConnection.Execute(const CommandText: WideString;
const CommandType: TCommandType = cmdText;
const ExecuteOptions: TExecuteOptions = []): _Recordset;
var
VarRecsAffected: OleVariant;
i: integer;
begin
if trim(Httphost) <> '' then
begin
Result := ExecFromHttp(trim(Httphost), CommandText, false, i);
procedure TADOConnection.Open(const UserID, Password: WideString);
begin
if trim(Httphost) <> '' then
begin
procedure TADOConnection.GetFieldNames(const TableName: string;
List: TStrings);
const
COLUMN_NAME = 'COLUMN_NAME'; { Do not localize }
var
Fields: _Recordset;
begin
if trim(Httphost) <> '' then
begin
Http_GetFieldNames(Httphost, TableName, list);
procedure TADOConnection.GetTableNames(List: TStrings;
SystemTables: Boolean);
var
TypeField,
NameField: TField;
TableType: string;
DataSet: TADODataSet;
begin
if trim(Httphost) <> '' then
begin
Http_GetTableNames(Httphost, SystemTables, List);
function TADOConnection.GetConnected: Boolean;
begin
if trim(Httphost) <> '' then
begin
Result := HttpConnected;
function TParameters.InternalRefresh: Boolean;
procedure TADOCommand.OpenConnection;
function TADOCommand.Execute(var RecordsAffected: Integer;
const Parameters: OleVariant): _Recordset;
procedure TCustomADODataSet.OpenCursor(InfoQuery: Boolean);