关于ADO多线程访问数据库的解决方案。(100分)

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

chenyi_goodboy

Unregistered / Unconfirmed
GUEST, unregistred user!
前些日子,偷点空余时间上了delphibbs。看到大家都是对Ado多线程访问数据库存在着
一些疑问。自己也找了一些时间试了一下。找到了其原因为AdoConnection是非线程安全的。现在解决此种问题的方法只能用Raw Ado Com组件了。代码如下:
有不懂的可以和我联系。chenyi_hello@sina.com 希望对大家有帮助。
unit UMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,adoint,adodb, StdCtrls, DB,inifiles,Activex;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
ADOConnection1: TADOConnection;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
ConnectionObject: _Connection;
end;

var
Form1: TForm1;
implementation
uses UAdoThread;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
const
FSection = 'DataSet';
var
SysPath:string;
constr:string;
sInitCat:string;
sUserID:string;
sPassword:string;
sDataSour:string;
ini:TiniFile;
begin
memo1.Clear;
CoInitialize(nil);
CoCreateInstance(CLASS_Connection, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, IUnknown, ConnectionObject);
ConnectionObject.CursorLocation:=adUseClient;
SysPath := ExtractFilePath(Application.ExeName);
ini := TIniFile.Create(SysPath + 'Ini/Data.ini');
SetFileAttributes(pchar(SysPath+ 'Ini/Data.ini'),FILE_ATTRIBUTE_ARCHIVE);
sDataSour := ini.ReadString(FSection, 'Data Source', '127.0.0.1');
sInitCat := ini.ReadString(FSection, 'Initial Catalog', 'Pubs');
sUserID := ini.ReadString(FSection, 'User ID', 'sa');
sPassword := ini.ReadString(FSection, 'PassWord', '');
Constr := 'Provider=SQLOLEDB.1;'
+ 'Persist Security InfoPersist Security Info=false;'
+ 'Data Source=' + sDataSour + ';'
+ 'Initial Catalog=' + sInitCat + ';'
+ 'User ID=' + sUserID + ';'
+ 'Password=' + sPassword + ';';
Ini.Free;
ConnectionObject.ConnectionString:= Constr;
AdoConnection1.ConnectionString:=Constr;
AdoConnection1.Connected:=true;
ConnectionObject.Open(ConnectionObject.ConnectionString, sUserId, sPassword,
adConnectUnspecified);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
begin
memo1.Clear;
for i:=1 to 100do
TAdoMulitThread.Create(false,connectionObject);
for i:=1 to 100do
TAdoMulitThread.Create(false,AdoConnection1.ConnectionObject);

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
ADoconnection1.Connected:=false;
ConnectionObject.Close;
ConnectionObject:=nil;
CoUninitialize;
end;

end.

unit UAdoThread;
interface
uses
Classes,adoint,adodb,Activex,SysUtils,forms;
type
TAdoMulitThread = class(TThread)
private
{ Private declarations }
ConnectionObject:_Connection;
line:string;
protected
procedure Execute;
override;
procedure UpdateCaption;
public
constructor Create(CreateSuspended: Boolean;aConnectionObject:_Connection);overload;
end;

implementation
uses UMain;
{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TAdoMulitThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end;
}
{ TAdoMulitThread }
constructor TAdoMulitThread.Create(CreateSuspended: Boolean;
aConnectionObject: _Connection);
begin
ConnectionObject:=aConnectionObject;
inherited create(CreateSuspended);
self.FreeOnTerminate:=true;
end;

procedure TAdoMulitThread.Execute;
var
RecordsetObject: _Recordset;
begin
{ Place thread code here }
CoCreateInstance(CLASS_Recordset, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, IUnknown, RecordsetObject);
RecordSetObject.Open('select * from authors',ConnectionObject,adOpenKeyset,adLockOptimistic,adCmdText);
while not recordsetObject.EOFdo
begin
line:=line+RecordSetObject.Fields[2].Value+'--';
application.ProcessMessages;
recordsetObject.MoveNext;
end;
Synchronize(UpdateCaption);
RecordsetObject.Close;
RecordSetObject:=nil;
end;

procedure TAdoMulitThread.UpdateCaption;
begin
form1.Memo1.Lines.Add(line+'-------'+inttostr(Form1.Memo1.Lines.count+1));
end;

end.
 
不知道你怎么理解“非线程安全”的呢?
 
非线程安全我也了解的不是很多。
只是略知一二。
线程安全一般是多个线程对一些数据结构数据进行操作时需要同步来避免数据次序和内容的安全。
如链表的插入,删除时。譬如程序中的memo1的lines就是一个连表。你必须手工来控制
同步。要不然系统就出错了。
本人不才,只能了解到这个点了。希望高手们指点一二。
Adoconnection 原码中涌到了一个list来保存所有Ado的访问链表。
如果在多线程中同时打开多个记录集Connection 会在它的list中加入她们的引用。
而此list是线程非安全的。除非用TThreadList来代替。不知是否说对,请大家参考参考。
 
后退
顶部