数据库+线程的奇怪现象,解决立刻送分!做过的都要来看看啊(100分)

  • 主题发起人 主题发起人 gsl4361
  • 开始时间 开始时间
G

gsl4361

Unregistered / Unconfirmed
GUEST, unregistred user!
我做了个多线程的例子:
主线程中一个按钮1实现:查询一个数据库(db1)表(t1,仅1条记录),结果在grid中显示。另创建一个线程,用按钮2实现,查询统计另一个数据库(db2)表(t2,约200000条记录,需耗时10几秒),sql:='select count(*) as c from t2',结果在另一grid中显示。
程序执行时,我先执行按钮2,进行对200000记录的查询统计,然后立刻执行按钮1,现象:在按钮1执行完后,即统计完200000条记录后,才执行按钮1的查询。然而,我把按钮2的查询的sql改为:sql:='select * from t2',则执行正常,即现象:点击按钮2后,立刻点击按钮1,则会立刻查出t1的内容,10几秒后,查出t2表的200000记录。感觉,第一种做法好像线程之间有冲突似的,而第二种做法却执行的很好,代码都一样,只时sql语句不同,不知何故????
 
你实现的可能不是真正的多线程,多线程需要考虑多个数据库连接的
将你的代码贴出来,让大家给你分析分析
 
谢谢lich,!
源码如下:
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB, Buttons, Grids, DBGrids, ExtCtrls,
IAgaloLED,IdUDPServer, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, Sockets, IdAntiFreezeBase, IdAntiFreeze,
IdStack, IdSocketHandle, ImgList, RzAnimtr;
type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
DBGrid1: TDBGrid;
Button1: TButton;
DBGrid2: TDBGrid;
Button2: TButton;
DataSource1: TDataSource;
DataSource2: TDataSource;
ADOQuery1: TADOQuery;
ADOQuery2: TADOQuery;
ADOConnection2: TADOConnection;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

tquerythread= class(tthread)
private
FADOConnection:TADOConnection;
FADOQuery:TADOQuery;
fdatasource:tdatasource;
fqueryexception:exception;
procedure connectdatasource;
procedure showqryerror;
protected
procedure execute;override;
public
constructor create(adoconnection:tadoconnection;adoquery:tadoquery;datasource:tdatasource);virtual;
end;
var
Form1: TForm1;
implementation
constructor tquerythread.create(adoconnection:tadoconnection;adoquery:tadoquery;datasource:tdatasource);
begin
inherited create(true);
fadoquery:=adoquery;
fdatasource:=datasource;
freeonterminate:=true;
resume;
end;

procedure tquerythread.execute;
begin
try
fadoquery.Open;
synchronize(connectdatasource);
except
end;
end;

procedure tquerythread.connectdatasource;
begin
fdatasource.dataset:=fadoquery;
end;

procedure tquerythread.showqryerror;
begin
application.ShowException(fqueryexception);
end;

procedure runbackgroundquery(adoconnection:tadoconnection;adoquery:tadoquery;datasource:tdatasource);
begin
tquerythread.create(adoconnection,adoquery,datasource);
end;

{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var hthread:thandle;
threadid:word;
d,dd:tdatetime;
easid:string;
begin
d:=strtodatetime('2003-10-17 0:00:00');
dd:=strtodatetime('2003-10-17 23:59:59');
easid:='100-1-2';
with adoquery1do
begin
close;
sql.Clear;
sql.Add('select count(*) from alarm_info where alarm_time>=:d and alarm_time<=:dd');
//
parameters[0].Value:=d;
parameters[1].Value:=dd;
end;
runbackgroundquery(adoconnection1,adoquery1,datasource1);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
with adoquery2do
begin
close;
sql.Clear;
sql.Add('select * from t');
open;
end;
end;

end.


var
Form1: TForm1;
ss:integer;
implementation

constructor tquerythread.create(adoconnection:tadoconnection;adoquery:tadoquery;datasource:tdatasource);
begin
inherited create(true);
fadoquery:=adoquery;
fdatasource:=datasource;
freeonterminate:=true;
resume;
end;

procedure tquerythread.execute;
begin
try
fadoquery.Open;
synchronize(connectdatasource);
except
end;

end;

procedure tquerythread.connectdatasource;
begin
fdatasource.dataset:=fadoquery;
end;

procedure tquerythread.showqryerror;
begin
application.ShowException(fqueryexception);
end;

procedure runbackgroundquery(adoconnection:tadoconnection;adoquery:tadoquery;datasource:tdatasource);
begin
tquerythread.create(adoconnection,adoquery,datasource);
end;

//function querythread(p:pointer):longint;stdcall;
//begin
//runbackgroundquery(adoconnection1,adoquery1,datasource1);
//end;
//
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var hthread:thandle;
threadid:word;
d,dd:tdatetime;
easid:string;
begin
d:=strtodatetime('2003-10-17 0:00:00');
dd:=strtodatetime('2003-10-17 23:59:59');
easid:='100-1-2';
with adoquery1do
begin
close;
sql.Clear;
sql.Add('select count(*) from alarm_info where alarm_time>=:d and alarm_time<=:dd');
//
parameters[0].Value:=d;
parameters[1].Value:=dd;
end;
runbackgroundquery(adoconnection1,adoquery1,datasource1);
{ with adoquery2do
begin
close;
sql.Clear;
sql.Add('select rno,eas_id,eas_name,eas_ip,alarm_time from alarm_info where alarm_time>=:d and alarm_time<=:dd');
parameters[0].Value:=d;
parameters[1].Value:=dd;
end;
runbackgroundquery(adoconnection2,adoquery2,datasource2);
}
end;

procedure TForm1.Button2Click(Sender: TObject);
var
I: Integer;
s:string;
begin
for I := 0 to 1000000do
// Iterate
begin
s:=inttostr(i);
end;
// for
edit1.Text:=s;
end;
// runbackgroundquery(adoconnection2,adoquery2,datasource2);
//end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
if l.LedOn=true then
l.LedOn:=false
else
l.LedOn:=true;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
d,dd:tdatetime;
begin
d:=strtodatetime('2003-10-17 0:00:00');
dd:=strtodatetime('2003-10-17 23:59:59');
with adoquery3do
begin
close;
sql.Clear;
sql.Add('select * from alarm_info where alarm_time>=:d');
parameters[0].Value:=d;
open;
end;
end;

procedure TForm1.UDPServerUDPRead(Sender: TObject;
AData: TStream;
ABinding: TIdSocketHandle);
var
s:string;
i,sum:integer;
op:tlocateoptions;
begin
l.LedOn:=true;
adocommand1.CommandText:='insert into t(a) values(:s)';
adocommand1.Parameters[0].Value:=s;
adocommand1.Execute;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
if l.LedOn=true then
//颜色不为本身默认值和报警后的值时
begin
ss:=ss+1;
if (ss<2) then
beep()
else
begin
l.LedOn:=false;
ss:=0;
end;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
UDPSERVER.Binding.IP:='192.168.0.210';
UDPSERVER.Binding.Port:=9901;
UDPSERVER.Active:=TRUE;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
adoquery1.Close;
adoquery2.Close;
end;

procedure TForm1.Button5Click(Sender: TObject);
var
d,dd:tdatetime;
begin
d:=strtodatetime('2003-10-17 0:00:00');
dd:=strtodatetime('2003-10-17 23:59:59');
with adoquery4do
begin
close;
sql.Clear;
sql.Add('select * from t');
// sum(cx) as c
open;
end;

end;
procedure TForm1.Button6Click(Sender: TObject);
var
s:string;
op:tlocateoptions;
i,sum:integer;
begin
{adocommand1.CommandText:='insert into t(a) values(:s)';
adocommand1.Parameters[0].Value:=s;
adocommand1.Execute;
}
adoquery4.Open;
//adotable1.Locate('a','333',op);
end;

end.
 
……
(t2,约200000条记录,需耗时10几秒),
……
点击按钮2后,立刻点击按钮1,则会立刻查出t1的内容,10几秒后,查出t2表的200000记录。感觉,第一种做法好像线程之间有冲突似的,而第二种做法却执行的很好,代码都一样,只时sql语句不同,不知何故????
看起来好像是正常的现象,本来t2就费时间
 
sorry 各位,我把源码又重新整理了一下,只把有用的贴出来,劳烦大家再看看,谢谢!
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB, Grids, DBGrids;
type
TForm1 = class(TForm)
DBGrid1: TDBGrid;
DataSource1: TDataSource;
ADOQuery1: TADOQuery;
ADOConnection1: TADOConnection;
DBGrid4: TDBGrid;
ADOQuery4: TADOQuery;
DataSource4: TDataSource;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
tquerythread= class(tthread)
private
FADOConnection:TADOConnection;
FADOQuery:TADOQuery;
fdatasource:tdatasource;
fqueryexception:exception;
procedure connectdatasource;
procedure showqryerror;
protected
procedure execute;override;
public
constructor create(adoconnection:tadoconnection;adoquery:tadoquery;datasource:tdatasource);virtual;
end;
var
Form1: TForm1;
implementation
constructor tquerythread.create(adoconnection:tadoconnection;adoquery:tadoquery;datasource:tdatasource);
begin
inherited create(true);
fadoquery:=adoquery;
fdatasource:=datasource;
freeonterminate:=true;
resume;
end;

procedure tquerythread.execute;
begin
try
fadoquery.Open;
synchronize(connectdatasource);
except
end;
end;

procedure tquerythread.connectdatasource;
begin
fdatasource.dataset:=fadoquery;
end;

procedure tquerythread.showqryerror;
begin
application.ShowException(fqueryexception);
end;

procedure runbackgroundquery(adoconnection:tadoconnection;adoquery:tadoquery;datasource:tdatasource);
begin
tquerythread.create(adoconnection,adoquery,datasource);
end;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var hthread:thandle;
threadid:word;
d,dd:tdatetime;
easid:string;
begin
d:=strtodatetime('2003-10-17 0:00:00');
dd:=strtodatetime('2003-10-17 23:59:59');
easid:='100-1-2';
with adoquery1do
begin
close;
sql.Clear;
sql.Add('select count(*) from alarm_info where alarm_time>=:d and alarm_time<=:dd');
//这句改成 select * 就没问题
parameters[0].Value:=d;
parameters[1].Value:=dd;
end;
runbackgroundquery(adoconnection1,adoquery1,datasource1);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
with adoquery4do
begin
close;
sql.Clear;
sql.Add('select * from t');
open;
end;
end;

end.
 
我想问一下,ADO的一个连接是否支持多线程呢?
 
不支持
ADO本身就不是线程安全的。
 
TADOConnection,在线程里面动态创建,一个线程用一个TADOConnection不会出错
 
后退
顶部