多线程与ADO ( 积分: 200 )

  • 主题发起人 主题发起人 qiubole
  • 开始时间 开始时间
Q

qiubole

Unregistered / Unconfirmed
GUEST, unregistred user!
想问一下,ADOQUERY是不是线程安全的,如果不是,我用Synchronize封装之后呢.
我用的是同一个连接,连接ACCESS数据库.
但有时会出现,数据库文件被独占.
代码如下.
TUpdateThread = class(TThread)
private
FADOQuery: TADOQuery;
FExecADO: TADOQuery;
TableA, TableB, TableC: string;
SaveADOConnection: TADOConnection;
LocalADOConnection: TADOConnection;
proceduredo
UpdateSale;
public
constructor Create(ATable, BTable, CTable: string;
LocalADO, ADOConnection: TADOConnection;
ASusped: Boolean);
destructor Destroy;
override;
procedure Execute;
override;
end;

constructor TUpdateThread.Create(ATable, BTable, CTable: string;
LocalADO, ADOConnection: TADOConnection;
ASusped: Boolean);
begin
TableA := ATable;
TableB := BTable;
TableC := CTable;
SaveADOConnection := ADOConnection;
LocalADOConnection := LocalADO;
FADOQuery := TADOQuery.Create(nil);
FExecADO := TADOQuery.Create(nil);
FADOQuery.Connection := LocalADOConnection;
FExecADO.Connection := SaveADOConnection;
Inherited Create(ASusped);
end;

destructor TUpdateThread.Destroy;
begin
FADOQuery.Free;
FExecADO.Free;
inherited;
end;

procedure TUpdateThread.DoUpdateSale;
var
tmpSQLStr: string;
begin
FADOQuery.Close;
FADOQuery.SQL.Text := 'select * from hs_000a';
FADOQuery.Open;
FExecADO.Close;
FExecADO.SQL.Text :=
'insert into ' + TableA + ' (did, dinsetcode, dno, ddate, dtime, dnum, dprice, '
+ ' dmoney_sale, dmoney_ss, dworker, dcard_no, dsale_state, '
+ ' ddiskname, dsubshop, djf) values('
+ ' :Did, :DBarcode, :DNo, :DDate, :Dtime, :DNum, :Dprice, '
+ ' :DMoney_Sale, :DMoney_SS, :DWorker, :DCard_No, :DSale_State, '
+ ' :DDiskName, :DSubShop, :DJF)';
FExecADO.Prepared := True;
while FADOQuery.RecordCount > 0do
begin
if Terminated then
Exit;
with FExecADO.Parameters, FADOQuerydo
begin
ParamByName('did').Value := FieldByName('did').AsString;
ParamByName('dbarcode').Value := FieldByName('dbarcode').AsString;
ParamByName('dNo').Value := FieldByName('dNo').AsString;
ParamByName('dDate').Value := FieldByName('DDate').AsDateTime;
ParamByName('dtime').Value := FieldByName('dtime').AsString;
ParamByName('dnum').Value := FieldByName('dnum').AsVariant;
ParamByName('dprice').Value := FieldByName('dprice').AsVariant;
ParamByName('dmoney_sale').Value := FieldByName('dmoney_sale').AsVariant;
ParamByName('dmoney_ss').Value := FieldByName('dmoney_ss').AsVariant;
ParamByName('dworker').Value := FieldByName('dworker').AsString;
ParamByName('dcard_no').Value := FieldByName('dcard_no').AsString;
ParamByName('dsale_state').Value := FieldByName('dsale_state').AsString;
ParamByName('DDiskName').Value := FieldByName('DDiskName').AsString;
ParamByName('dsale_state').Value := FieldByName('dsale_state').AsString;
ParamByName('DSubShop').Value := '0001';
ParamByName('DJF').Value := FieldByName('djf').AsFloat;
end;
// with
FExecADO.ExecSQL;
FADOQuery.Delete;
end;
end;

procedure TUpdateThread.Execute;
label Loop1;
var
tmpSQLStr: string;
tmpUpdateCount: Integer;
tmpUpdateLast: Boolean;
begin
CoInitialize(nil);
Priority := tpLowest;
FreeOnTerminate := True;
if not LocalADOConnection.Connected then
LocalADOConnection.Connected := True;
if not SaveADOConnection.Connected then
LocalADOConnection.Connected := True;

tmpUpdateCount := 0;
while Truedo
begin
if Terminated then
begin
Break;
end;

try
EnterCriticalSection(SystemSetup.FSaleUpLock);
Self.Synchronize(DoUpdateSale);
finally
LeaveCriticalSection(SystemSetup.FSaleUpLock);
end;

//如果出错,表明网络有问题,需要进行挂起。
Self.Suspend;
end;

end;
 
想问一下,ADOQUERY是不是线程安全的,如果不是,我用Synchronize封装之后呢.
我用的是同一个连接,连接ACCESS数据库.
但有时会出现,数据库文件被独占.
代码如下.
TUpdateThread = class(TThread)
private
FADOQuery: TADOQuery;
FExecADO: TADOQuery;
TableA, TableB, TableC: string;
SaveADOConnection: TADOConnection;
LocalADOConnection: TADOConnection;
proceduredo
UpdateSale;
public
constructor Create(ATable, BTable, CTable: string;
LocalADO, ADOConnection: TADOConnection;
ASusped: Boolean);
destructor Destroy;
override;
procedure Execute;
override;
end;

constructor TUpdateThread.Create(ATable, BTable, CTable: string;
LocalADO, ADOConnection: TADOConnection;
ASusped: Boolean);
begin
TableA := ATable;
TableB := BTable;
TableC := CTable;
SaveADOConnection := ADOConnection;
LocalADOConnection := LocalADO;
FADOQuery := TADOQuery.Create(nil);
FExecADO := TADOQuery.Create(nil);
FADOQuery.Connection := LocalADOConnection;
FExecADO.Connection := SaveADOConnection;
Inherited Create(ASusped);
end;

destructor TUpdateThread.Destroy;
begin
FADOQuery.Free;
FExecADO.Free;
inherited;
end;

procedure TUpdateThread.DoUpdateSale;
var
tmpSQLStr: string;
begin
FADOQuery.Close;
FADOQuery.SQL.Text := 'select * from hs_000a';
FADOQuery.Open;
FExecADO.Close;
FExecADO.SQL.Text :=
'insert into ' + TableA + ' (did, dinsetcode, dno, ddate, dtime, dnum, dprice, '
+ ' dmoney_sale, dmoney_ss, dworker, dcard_no, dsale_state, '
+ ' ddiskname, dsubshop, djf) values('
+ ' :Did, :DBarcode, :DNo, :DDate, :Dtime, :DNum, :Dprice, '
+ ' :DMoney_Sale, :DMoney_SS, :DWorker, :DCard_No, :DSale_State, '
+ ' :DDiskName, :DSubShop, :DJF)';
FExecADO.Prepared := True;
while FADOQuery.RecordCount > 0do
begin
if Terminated then
Exit;
with FExecADO.Parameters, FADOQuerydo
begin
ParamByName('did').Value := FieldByName('did').AsString;
ParamByName('dbarcode').Value := FieldByName('dbarcode').AsString;
ParamByName('dNo').Value := FieldByName('dNo').AsString;
ParamByName('dDate').Value := FieldByName('DDate').AsDateTime;
ParamByName('dtime').Value := FieldByName('dtime').AsString;
ParamByName('dnum').Value := FieldByName('dnum').AsVariant;
ParamByName('dprice').Value := FieldByName('dprice').AsVariant;
ParamByName('dmoney_sale').Value := FieldByName('dmoney_sale').AsVariant;
ParamByName('dmoney_ss').Value := FieldByName('dmoney_ss').AsVariant;
ParamByName('dworker').Value := FieldByName('dworker').AsString;
ParamByName('dcard_no').Value := FieldByName('dcard_no').AsString;
ParamByName('dsale_state').Value := FieldByName('dsale_state').AsString;
ParamByName('DDiskName').Value := FieldByName('DDiskName').AsString;
ParamByName('dsale_state').Value := FieldByName('dsale_state').AsString;
ParamByName('DSubShop').Value := '0001';
ParamByName('DJF').Value := FieldByName('djf').AsFloat;
end;
// with
FExecADO.ExecSQL;
FADOQuery.Delete;
end;
end;

procedure TUpdateThread.Execute;
label Loop1;
var
tmpSQLStr: string;
tmpUpdateCount: Integer;
tmpUpdateLast: Boolean;
begin
CoInitialize(nil);
Priority := tpLowest;
FreeOnTerminate := True;
if not LocalADOConnection.Connected then
LocalADOConnection.Connected := True;
if not SaveADOConnection.Connected then
LocalADOConnection.Connected := True;

tmpUpdateCount := 0;
while Truedo
begin
if Terminated then
begin
Break;
end;

try
EnterCriticalSection(SystemSetup.FSaleUpLock);
Self.Synchronize(DoUpdateSale);
finally
LeaveCriticalSection(SystemSetup.FSaleUpLock);
end;

//如果出错,表明网络有问题,需要进行挂起。
Self.Suspend;
end;

end;
 
ado是线程安全的,但在动态库中时要CoInitialize初始化com
 
每个线程要有自己的ADOConnection,
要么就自己使用临界区等解决线程同步问题
 
每个线程要有自己的ADOConnection?天,如果对于ACCESS这样的文件型数据库,不会造成文件锁吗?我现在共用同一个连接也会锁死
 
procedure TUpdateThread.Execute;
label Loop1;
var
tmpSQLStr: string;
tmpUpdateCount: Integer;
tmpUpdateLast: Boolean;
begin
CoInitialize(nil);
Priority := tpLowest;
FreeOnTerminate := True;
if not LocalADOConnection.Connected then
LocalADOConnection.Connected := True;
if not SaveADOConnection.Connected then
LocalADOConnection.Connected := True;

tmpUpdateCount := 0;
while not Terminateddo
begin
try
do
UpdateSale;
except
//如果出错,表明网络有问题,需要进行挂起。
Self.Suspend;
end;
end;
1、如果不确定adoconnection是否线程安全,还是在线程中动态创建保险。
2、你的线程中的同步不要用,另外临界区保护好像也作用不大
3、如果出错挂起线程这一步不知道是怎么考虑的,觉得有问题
4、通过网络共享使用access好象问题多多
 
多线程,还的进行访问的临界区控制,可以参考一下多客户同时访问一个数据库的处理方法。
 
adoconnection好象并不时线程安全的哦,以前听某位大侠说过
 
数据库最好该用sql server,而且支持网络的,还有就是每个线程里面都有专门的adoconnection,而且都是在线程里面创建的,不要拖在窗体上,这样一般没有问题的.
 
我现在用的就是cqwty说的:
每个线程里面都有专门的adoconnection,而且都是在线程里面创建的
并且Query也是一样。
Except的时候注意释放 adoconnection ,Query
 
ADOQUERY是线程安全的,不用考虑太多。数据库软件也都有锁的机制,可以让数据库操作不会出现冲突。
 
1.在使用ParamByName方式,操作数据库时经常会发生数据库死锁!
建议使用字符串直接拼装成SQL语句就不会出现数据库死锁的问题!(我已经测试过了)

2.在循环内拼装多条SQL语句然后再循环外一次执行可以提高效率!
 
ado控件不是线程序安全的.这点不需要争论!
每个线程使用一组ADO控件是可以解决问题的,但要考虑连接数量的限制.
顺便说一下,ADOConnection是多线程运行的.当连接线程是不是每个打开的数据集合使用一个就不知道了.
如果必须使用一组控件完成数据访问,必须同步调用ADO控件,即使用临界、信号量等方法将要使用的控件调用方法保护起来。
 
为什么每个线程要使用一组ADO控件?这样不是每个ADO都是占用一个连接?如果客户端多的话,一个客户端就多个连接,线程多的话,不是就会造成服务器的困难吗?
如果封装成DLL或者COM,都是可以从现有的ADO中继承的,也要以不必每个COM都用不有的ADO。
 
一个程序里面,使用两个ADOConnection连接同一个数据库,已经是在干蠢事了!
使用多个ADOQuery,则可以理解,因为查询内容,当前定位不同!如果查询相同,
那么公用一个也无妨,但要在Synchronize结束前记住RecNo,再进入时恢复,
Synchronize是让控件排着队轮流在主线程里面干活,有问题也怪不到多线程头上!
 
至appfirst 。
adocommend和adoquery是线程安全的,adoconnection就不是的。
 
后退
顶部