Multi-threading (FireDAC)

De RAD Studio
Aller à : navigation, rechercher

Remonter à Utilisation des connexions (FireDAC)


Cette rubrique explique comment utiliser FireDAC dans un environnement multithread.

Informations générales

FireDAC est adapté aux opérations relatives aux threads si les conditions suivantes sont satisfaites :

  • Un objet connexion et tous les objets qui y sont associés (tels que TFDQuery, TFDTransaction, etc.) sont utilisés par un seul thread à chaque moment.
  • FDManager est activé avant le démarrage des threads, en définissant FDManager.Active sur True.

Cela signifie qu'après l'ouverture d'une requête par un thread et jusqu'à ce que son traitement soit terminé, l'application ne peut pas utiliser cette requête ni les objets connexion dans un autre thread. De même, après le démarrage d'une transaction par un thread et jusqu'à ce que la transaction soit terminée, l'application ne peut pas utiliser cette transaction ni les objets connexion dans un autre thread.

Dans la pratique, cela signifie qu'une application doit sérialiser l'accès à une connexion sur tous les threads, ce qui n'est pas pratique. Le non-respect de ces règles peut entraîner un comportement anormal, des erreurs de violation d'accès et d'autres erreurs telles que l'erreur SQL Server "La connexion est occupée avec les résultats d'une autre commande".

La simplification standard consiste à créer et à utiliser pour chaque thread un objet connexion dédié fonctionnant avec la base de données. Dans ce cas, aucune sérialisation supplémentaire n'est requise. Par exemple, le code suivant réalise des tâches de base de données dans des threads :

type
  TDBThread = class(TThread)
  protected
    procedure Execute; override;
  end;

procedure TDBThread.Execute;
var
  oConn: TFDConnection;
  oPrc: TFDQuery;
begin
  FreeOnTerminate := False;
  oConn := TFDConnection.Create(nil);
  oConn.ConnectionDefName := 'Oracle_Pooled'; // see next section
  oPrc := TFDStoredProc.Create(nil);
  oPrc.Connection := oConn;
  try
    oConn.Connected := True;
    oPrc.StoredProcName := 'MY_LONG_RUNNING_PROC';
    oPrc.ExecProc;
  finally
    oPrc.Free;
    oConn.Free;
  end;
end;
 
 // main application code
var
  oThread1, oThread2: TDBThread;
begin
  FDManager.Active := True;
  ...
  oThread1 := TDBThread.Create(False);
  oThread2 := TDBThread.Create(False);
  ...
  oThread1.WaitFor;
  oThread1.Free;
  oThread2.WaitFor;
  oThread2.Free;
end;

Remarque : Pour le cas ci-dessus où l'application exécute une seule requête SQL en arrière-plan, utilisez le mode d'exécution asynchrone des requêtes.

Remarque : Une application multithread peut fermer les connexions ouvertes dans les threads d'arrière-plan dans un gestionnaire d'événement TFDManager.BeforeShutdown pour éviter un éventuel verrou mortel.

Mise en pool des connexions

L'établissement d'une connexion représente l'une des opérations coûteuses d'interaction avec les bases de données. Dans une application multithread, où chaque thread démarre, établit une connexion, effectue une certaine tâche courte et libère la connexion, les établissements de connexion répétés peuvent entraîner une dégradation des performances dans tout le système. Pour éviter ce problème, l'application peut avoir recours à la mise en pool des connexions.

La mise en pool des connexions peut uniquement être activée pour une définition de connexion persistante ou privée en définissant Pooled=True. Pour une définition persistante :

[Oracle_Pooled]
DriverID=Ora
Database=ORA_920_APP
User_Name=ADDemo
Password=a
Pooled=True

ou pour une définition privée :

var
  oParams: TStrings;
begin
  oParams := TStringList.Create;
  oParams.Add('Database=ORA_920_APP');
  oParams.Add('User_Name=ADDemo');
  oParams.Add('Password=a');
  oParams.Add('Pooled=True');
  FDManager.AddConnectionDef('Oracle_Pooled', 'Ora', oParams);
  .....................
  FDConnection1.ConnectionDefName := 'Oracle_Pooled';
  FDConnection1.Connected := True;

Aucun paramètre supplémentaire ne peut être spécifié dans la propriété TFDConnection.Params, car toutes les connexions mises en pool doivent partager les mêmes paramètres de connexion.

Définir TFDConnection.Connected sur True permet d'acquérir une connexion physique à partir du pool. Définir TFDConnection.Connected sur False libère la connexion physique dans le pool, mais laisse la connexion ouverte. Pour fermer et détruire toutes les connexions physiques mises en pool, l'application peut appeler la méthode TFDManager.CloseConnectionDef :

FDManager.CloseConnectionDef('Oracle_Pooled');

ou fermer le gestionnaire de pilote FireDAC en appelant :

FDManager.Close;


Des paramètres de définition de connexion supplémentaires peuvent être spécifiés pour configurer un pool :

Paramètre Paramètre Exemple
POOL_CleanupTimeout Temps (en millisecondes) restant jusqu'à ce que FireDAC supprime les connexions qui n'ont pas été utilisées pendant une période plus longue que le temps POOL_ExpireTimeout. La valeur par défaut est 30000 millisecondes (30 secondes). 3600000
POOL_ExpireTimeout Temps (en millisecondes) au bout duquel la connexion inactive peut être supprimée du pool et détruite. La valeur par défaut est 90000 millisecondes (90 secondes). 600000
POOL_MaximumItems Nombre maximal de connexions dans le pool. Si l'application requiert davantage de connexions, une exception est déclenchée. La valeur par défaut est 50. 100

Voir aussi

Exemples