I am using mutiple connection using ODBC. In whole project I am using the same connection, but create, use and destory TQuery object. Now I am going to use connection in threads and came to know Delphi BDE provides TSession Class for that. I want to know how to use TSession for concurrent operation, please provide code sample for that if possible.
-
BDE ? in 2013 ? with Windows 8.1 near release ? With support from Embarcadero dropped long ago? you mast be joking... Find some direct ODBC connection lib on Torry.net or switch to something else. UniDAC, FireDAC, DB-Express, ADO, ZeosDB, whatever. And regarding tags, do you really use Delphi 2009 till XE2, 4 different versions at once ? – Arioch 'The Apr 18 '13 at 16:47
-
No, let's not tag with made up versions. If you have a specific version that you want to use, add that one version as a tag. – David Heffernan Apr 18 '13 at 16:59
-
6Wayback machine paging JohnKaster or MarkEdington... – dthorpe Apr 18 '13 at 17:10
-
@Ashu -- Seriously, do not use TQuery, TTable, TStoredProc, TDatabase, or TSession. – Nick Hodges Apr 18 '13 at 19:41
-
@Ashu If you feel that the answer provided is correct, please accept it as the answer – Cary Jensen May 21 '13 at 13:44
1 Answers
While I agree that the BDE is old, it is possible to create thread-safe access to the database using the BDE and TSessions.
Consider this. When two copies of the same application are running at the same time, the database engine or database server distinguishes between the two instances for the purpose of record and table locking. This distinction is possible because each application uses a separate connection, or in the case of the BDE, session.
The session is represented by a TSession instance. In single threaded projects the TSession is created for you. If you want to connect to the BDE with two or more threads, each should have its own TSession.
Using multiple TSessions is demonstrated here, in this really old code example that I dug up (it is old, and I would do it differently today, but you asked for it). The trick is that each session needs to have the same network directory and have a unique private directory. Here is the TThread descendant:
type
TWriteData = class(TThread)
private
FSQL: String;
FFileName: String;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean; const SQL: String;
const FileName: String); override; overload;
end;
Here is the overridden constructor:
constructor TWriteData.Create(CreateSuspended: Boolean;
const SQL: String; const FileName: String);
begin
inherited Create(True);
FSQL := SQL;
FFileName := String;
end;
And here is the execute method. Importantly, the TSession.PrivateDir is set to a unique directory name (based on the ThreadID). Could also use a GUID, or some other value, as long as it is unique. Note also that Session1 is a TSession component on the data module, and Query1 is a TQuery that uses a TDatabase (Database1), which in turn uses Session1. Session is a variable declared in the Bde.DBTables unit. This variable refers to the default TSession that the BDE creates for the BDE TDataSets that are active in the primary thread of execution.
procedure TWriteData.Execute;
var
DataMod: TDataModule1;
AppDir: String;
begin
AppDir := ExtractFilePath(Application.ExeName);
DataMod := TDataModule1.Create(nil);
try
with DataMod do
begin
//All sessions need a unique private directory
Session1.PrivateDir := AppDir + IntToStr(Self.ThreadID);
//All sessions share a common network control file
Session1.NetFileDir := Session.NetFileDir;
ForceDirectories(Session1.PrivateDir);
try
Query1.SQL.Text := FSQL;
ClientDataSet1.Open;
ClientDataSet1.SaveToFile(AppDir + FFileName);
ClientDataSet1.Close;
finally
SysUtils.RemoveDir(Session1.PrivateDir);
end; //try
end; //begin
finally
DataMod.Free;
end;
end;
I hope this helps.

- 3,751
- 3
- 32
- 55
-
Thanks Cary.. :) I am currently using TDatabase to connect to database. We connect at the statrting of application and keep connection till end. Now refactoring code for mutithreading should I use TSession for connection and diffrent thread should have their own session. Using TSession Should I connect and disconnect everytime we use the database. How Can I open database as shared connection and do the concurrent operation. – Ashu Apr 22 '13 at 20:25
-
Each thread must have its own TSession, which means that each thread must have a separate TDatabase. You cannot open a database and share it concurrently unless you use a synchronization object, such as a TCriticalSection, to prevent two threads from accessing the database at the same time. If you need truly concurrent access, you must use a different TSession and TDatabase for each thread. If you do not have a limit on the number of simultaneous users, you can open a connection (TSession and TDatabase) and use it for the life of the thread. Please accept the answer if this helps. – Cary Jensen Apr 25 '13 at 23:20
-
Another option is to use a connection pool. I wrote an article about using a Semaphore to manage a connection pool. This article, and a connection pool sample, is available on the Embarcadero Developer Network (edn.embarcadero.com). Search for my name and Semaphore or Connection pool. While a connection pool permits you to use the same set of connections from multiple threads, it introduces a new set of its own complexities. I would stick to creating a new connection on each thread unless you find the overhead of creating a new connection for each thread to be a problem. – Cary Jensen Apr 25 '13 at 23:25