如何从客户端一次性地向远程的服务器导入大量的数据?(分布式多层应用)(200分)

  • 主题发起人 主题发起人 caojun77
  • 开始时间 开始时间
C

caojun77

Unregistered / Unconfirmed
GUEST, unregistred user!
目前这套系统的结构是:应用程序服务器和数据库服务器(MS SQL Server 7.0)都在局域网内的同一台服务器上;而客户端则在局域网内的另外一台机器上。

——>对于应用程序服务器来说,其主要构成就是一个Remote Data Module,在这个远程数据模块中,放置有下述三个构件:TADOConnection,TADOQuery和TDataSetProvider。
本来是想利用客户端的TClientDataSet的CommandText属性,这样比较方便,但是CommandText的类型属于String;而从客户端传来的每一条记录的SQL语句实在是太长了,并且该SQL语句的类型属于TStrings,
譬如:有这样的一条插入记录的SQL语句:
Insert into House_Sale(HouseID,UID,PropertyName,RentSale,Prince,City,District,Address,Mright,
Purpose,HouseType,BuildingType,Floor,HouseYear,BuildingArea,LivingArea,Direction,Telephone,
ContactPerson,UserCode,Email,BuyReason,LimitDate,Price,PriceType,PropertyFee,PropertyFeeType,
Taxes,Gas,Water,Electricity,Kitchen,Toilators,Equipment,Bus,SaleDesp,IsShow,Fitment,Parklod,
BrokerUserName)
values('HID2000122100155','20001221',NULL,'1','上海','上海','徐汇','(编号为:0100520003)罗秀路1095弄',
'售后','住宅','二室','多层','1',0,0,'11.9+8.29',NULL,'64223038','汇成置换','MA000928HC',NULL,NULL,
0,10,'万元/套',0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL)

为了解决这个问题,我采用了在应用程序服务器的TDataSetProvider中加入OnDataRequest事件处理函数,这样就会和客户端的TClientDataSet的DataRequest相呼应。OnDataRequest事件处理函数如下:
function TRDM_mtdata.dspHouse_SaleDataRequest(Sender: TObject;
Input: OleVariant): OleVariant;
begin
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Text:=Input;
Input:=null;
ADOQuery1.ExecSQL;
end;

——>对于客户端来说,我的想法是这样的:先将客户端本地的数据源从Access数据库中取出并显示在客户端的DBGrid中,然后通过远程的应用程序服务器向MS SQL Server 7.0上的一个表导入大约300条这样的数据。
在这里我用了下列两组控件:
一、TDatabase,TTable,TDataSource和TDBGrid,使用这组控件的目的是:将客户端本地的数据源从Access数据库中取出并显示在客户端的DBGrid中。
二、TSocketConnection、TClientDataSet和TQuery,使用这组控件的目的是:通过TQuery的SQL属性为本地的每一条记录构造一条SQL插入语句,并以参数的形式将其传递给TClientDataSet的DataRequest方法,最终通过
TSocketConnection和远程的应用程序服务器的TDataSetProvider进行通讯。
导入数据的具体源代码如下:
procedure Tfrm_House_Sale.BitBtn3Click(Sender: TObject);
var iField,i:Integer;
desttbl,sql_House_Sale:string;
begin
i:=1;
with Table1 do
begin
Open; {打开老系统的表}
desttbl:='House_Sale';
while EOF=FALSE do
begin
{逐条记录处理}
qryInsert.SQL.Text:='';
qryInsert.sql.Add('Insert into '+desttbl + '(');
for iField:=0 to dbg.FieldCount-1 do
begin
qryInsert.sql.add
(dbg.Fields[iField].DisplayLabel);
if iField<>dbg.FieldCount-1 then
qryInsert.sql.add(',');
end;
qryInsert.sql.add(') values(');
for iField:=0 to dbg.FieldCount-1 do
begin
{进行数据类型转换}
if dbg.fields[iField].DataType=ftInteger then
qryInsert.sql.add(inttostr
(dbg.fields[iField].asInteger));
if dbg.fields[iField].DataType=ftFloat then
qryInsert.sql.add(floattostr
(dbg.fields[iField].asFloat));
if dbg.fields[iField].DataType=ftString then
begin
if dbg.fields[iField].asString<>'' then
qryInsert.sql.add(''''+dbg.fields
[iField].asString+'''')
else
qryInsert.sql.add('NULL');
end;
if dbg.fields[iField].DataType=ftMemo then
begin
if dbg.fields[iField].asString<>'' then
qryInsert.sql.add(''''+dbg.fields
[iField].asString+'''')
else
qryInsert.sql.add('NULL');
end;
if iField<>dbg.FieldCount-1
then qryInsert.sql.add(',');
end;
qryInsert.sql.add(')');

with ClientDataSet1 do
begin
// Close;
DataRequest(qryInsert.sql.Text);
//Open;
end;

ProgressBar1.Position := i;
i:=i+1;
next;
end;
ShowMessage('转换完毕!');
end;
end;

问题列表:
一、我在本地的机器上(即:MS SQL Server 7.0、应用程序服务器和客户端都存在于同一台机器上),数据导入工作一直正常。但一旦将MS SQL Server 7.0和应用程序服务器放于局域网内的另外一台机器上时,再进行调试,就出错,具体表征如下:
1、完全能成功地将300条记录导入SQL Server中的概率是30%左右;多数情况是,在导入了一部分记录后,客户端便没有任何反应了,最终在任务管理器中出现“没有响应”。
2、我尝试着将数据表中的记录减少,同时在任务管理器中将该进程的优先级人工地设为最高级别——实时,这样的话,成功的可能性较前者要高一些。
3、一般情况下,客户端没有响应后,并没有其它的出错提示信息;但有时会偶尔出现这样的提示信息:
BDE Error $000F,查阅有关资料后,得知:这可通过增加BDE Administrator中的Configuration->System->INI中的SharedMemSize来除错。试过之后,虽然不再出现BDE Error $000F这种出错信息,但能够成功地将数据导入SQL Server中的概率还是很低的。

二、对于我的这种情况,是要对BDE的有关参数进行设置,还是要对上述所使用控件的一些相关属性进行设置?
具体应当怎样进行设置?由于我在应用程序服务器端采用了ADO方式,不知运行有应用程序服务器的那台机器上的BDE是否也要进行相关设置?

三、是不是要对一些有关内存的大小、超时的控制或采用异步、同步的方式来进行设置?具体应当设置哪些?

四、不知上述我所采用的方式是不是本身就存在着不合理性?不知“流的方式”或“Sock/Socket方式”是怎样实现的?

附:我的客户端应用程序占用内存的情况以及系统的一些相关参数:
1、刚进入客户端应用程序时,大约占用2.3M的内存,然后进入正式导入数据的界面时,占用内存9-10M(因为此时要将本地的大量数据读入内存并且显示在DBGrid中),最后开始正式导入数据的工作,内存的占用量会不断地上升,一般当内存的占用量不超过11.5-12M时,完全成功的可能性比较大。
2、BDE Administrator中的Configuration->System->INI中的一些参数如下:
MAXBUFSIZE 2048
MAXFILEHANDLES 48
MEMSIZE 16
MINBUFSIZE 128
SHAREDMEMSIZE 2048


急!!急!!急!!急!!急!!急!!急!!急!!急!!急!!急!!急!!急!!急!!急!!急!!







 
干嘛,一次要导300条?
一条一条的来,虽然效率要低,但不致于“累死”吧!
去看看李维的那三本书吧!
 
我不知道你们局域网的情况怎样?我知道有个公司的局域网传输速度比上网速度还慢!!
 
To sportsman
你用80M的DDN上网吗?
 
做成stored procedures
速度会快些
 
是不是你的局域网有问题啊?我在我们公司里倒数据时,几个SQL Server都是在不同的机器
上,互相倒几万条的数据都没有问题的。
 
1.建议不要用TDbgrid,因为他的refresh很慢
2.最好用程序过程而不用query去生成insert语句
3.最好insert前检查一下数据的合法性
 
李维先生讲:1000是个神奇的数字,所以一次要导1000条,呵呵! :-)
 
多人接受答案了。
 
后退
顶部