Icon Multi-Threaded Applications

ElevateDB is internally structured to be thread-safe and usable within a multi-threaded application provided that you follow the rules that are outlined below.

Unique Sessions
ElevateDB requires that you use a unique TEDBSession component for every thread that must perform any database access at all. Each of these TEDBSession components must also be assigned a SessionName property value that is unique among all TEDBSession components in the application. Doing this allows ElevateDB to treat each thread as a separate and distinct session and will isolate transactions and other internal structures accordingly. You may use the AutoSessionName property of the TEDBSession component to allow ElevateDB to automatically name each session so that is unique or you may use code similar to the following:

var
   LastSessionValue: Integer;
   SessionNameSection: TRTLCriticalSection;

{ Assume that the following code is being executed
  within a thread }

function UpdateAccounts: Boolean;
var
   LocalSession: TEDBSession;   
   LocalDatabase: TEDBDatabase;
   LocalQuery:   TEDBQuery;
begin
   Result:=False;
   LocalSession:=GetNewSession;
   try
      LocalDatabase:=TEDBDatabase.Create(nil);
      try
         with LocalDatabase do
            begin
            { Be sure to assign the same session name
              as the TEDBSession component }
            SessionName:=LocalSession.SessionName;
            DatabaseName:='AccountsDB';
            Database:='Accounting';
            Connected:=True;
            end;
         LocalQuery:=TEDBQuery.Create(nil);
         try
            with LocalQuery do
               begin
               { Be sure to assign the same session and
                 database name as the TEDBDatabase
                 component }
               SessionName:=LocalSession.SessionName;
               DatabaseName:=LocalDatabase.DatabaseName;
               SQL.Clear;
               SQL.Add('UPDATE accounts SET PastDue=True');
               SQL.Add('WHERE DueDate < CURRENT_DATE'));
               Prepare;
               try
                  { Start the transaction and execute the query }
                  LocalDatabase.StartTransaction;
                  try
                     ExecSQL;
                     LocalDatabase.Commit;
                     Result:=True;
                  except
                     LocalDatabase.Rollback;
                  end;
               finally
                  UnPrepare;
               end;
               end;
         finally
            LocalQuery.Free;
         end;
      finally
         LocalDatabase.Free;
      end;
   finally
      LocalSession.Free;
   end;
end;

function GetNewSession: TEDBSession;
begin
   EnterCriticalSection(SessionNameSection);
   try
      LastSessionValue:=LastSessionValue+1;
      Result:=TEDBSession.Create(nil);
      with Result do
         SessionName:='AccountSession'+IntToStr(LastSessionValue);
   finally
      LeaveCriticalSection(SessionNameSection);
   end;
end;

{ initialization in application }
   LastSessionValue:=0;
   InitializeCriticalSection(SessionNameSection);
{ finalization in application }
   DeleteCriticalSection(SessionNameSection);

The AutoSessionName property is, by default, set to False so you must specifically turn it on if you want this functionality. You may also use the thread ID of the currently thread to uniquely name a session since the thread ID is guaranteed to be unique within the context of a process.

Unique Databases
Another requirement is that all TEDBDatabase components must also be unique and have values assigned to their SessionName properties that refer to the unique SessionName property of the TEDBSession component defined in the manner discussed above.

Unique Tables, Queries, and Stored Procedures
The final requirement is that all TEDBTable, TEDBQuery, TEDBScript, and TEDBStoredProc components must also be unique and have values assigned to their SessionName properties that refer to the unique SessionName property of the TEDBSession component defined in the manner discussed above. Also, if a TEDBTable or TEDBQuery component refers to a TEDBDatabase component's DatabaseName property via its own DatabaseName property, then the TEDBDatabase referred to must be defined in the manner discussed above.

ISAPI Applications
ISAPI applications created using the WebBroker components or a similar technology are implicitly multi-threaded. Because of this, you should ensure that your ISAPI application is thread-safe according to these rules for multi-threading when using ElevateDB. Also, if you have simply dropped a TEDBSession component on the WebModule of a WebBroker ISAPI application, you must set its AutoSessionName property to True before dropping any other ElevateDB components on the form so that ElevateDB will automatically give the TEDBSession component a unique SessionName property and propogate this name to all of the other ElevateDB components.

Further Considerations
There are some other things to keep in mind when writing a multi-threaded database application with ElevateDB, especially if the activity will be heavy and there will be many threads actively running. Be prepared to handle any errors in a manner that allows the thread to terminate gracefully and properly free any TEDBSssion, TEDBDatabase, TEDBTable, TEDBQuery, and TEDBStoredProc components that it has created. Otherwise you may run into a situation where memory is being consumed at an alarming rate. Finally, writing multi-threaded applications, especially with database access, is not a task for the beginning developer so please be sure that you are well-versed in using threads and how they work before jumping into writing a multi-threaded application with ElevateDB.
Image