Prise en charge du flux de valeurs Blob dans FireDAC

De RAD Studio
Aller à : navigation, rechercher

Remonter à Utilisation des commandes (FireDAC)


La technique du flux de valeurs BLOB aussi appelée "streaming" implémente le flux des valeurs de paramètres BLOB vers/à partir d'une base de données. Cela permet de transférer une valeur BLOB "par référence" au lieu de la transférer "par valeur". Les avantages de cette technique sont les suivants :

  • Consommation de la mémoire côté client minimisée, par rapport au transfert "par valeur" qui exige une consommation supplémentaire de mémoire égale à 3 ou 4 fois la taille de la valeur BLOB.
  • Performances 1,5 à 2 fois supérieures, par rapport aux performances du transfert "par valeur".
  • Capacité de mise à jour de la valeur BLOB "par segment", par rapport au transfert "par valeur" qui ne permet qu'une mise à jour complète de la valeur BLOB.

Les inconvénients sont les suivants :

  • Transformation du type de données/de l'encodage non effectuée pour la plupart des bases de données.
  • Pris en charge uniquement pour les paramètres de commande, pas pour les colonnes.

Les API qui transfèrent une valeur BLOB "par valeur" sont :

L'API relatif aux flux de valeurs BLOB inclut :

Usage

FireDAC propose deux types de flux de valeurs BLOB : les flux externes et les flux internes.

Flux externes

Un flux externe est fourni par l'application à FireDAC (externe à FireDAC). FireDAC va lire/écrire ce flux. Les flux externes sont pris en charge pour toutes les BD.

Pour utiliser le flux externe, l'application doit :

  • Facultativement, définir le paramètre DataType sur l'un des types de données BLOB, comme ftOraBlob, ftBlob, ftMemo, ftWideMemo. Dans le cas contraire, la prochaine assignation destinée à la propriété AsStream définira implicitement le type de données sur ftStream.
  • Facultativement, définir le paramètre ParamType. Cela définit le mode de transfert du flux :
    • ptInput - le flux va être lu et écrit dans une valeur BLOB de la BD.
    • ptOutput - une valeur BLOB de la BD va être lue et écrite dans un flux.
  • Assigner une référence de flux à la propriété AsStream du paramètre. Dans ce cas, FireDAC devient le propriétaire de la référence de flux. L'objet sera libéré après l'annulation d'une préparation de requête, ou après la prochaine affectation de valeur. Sinon, les applications peuvent utiliser la méthode SetStream du paramètre pour contrôler la propriété. Le flux sera utilisé à partir de la position de flux actuelle.
  • Exécuter la commande SQL.

Par exemple :

FDQuery1.SQL.Text := 'INSERT INTO tab (blobdata) VALUES (:blobdata)';
FDQuery1.Params[0].DataType := ftBlob;
// FireDAC takes ownership of the stream object
FDQuery1.Params[0].AsStream := TFileStream.Create('data.bin', fmOpenRead);
FDQuery1.ExecSQL;

Flux internes

Un flux interne est fourni par FireDAC à l'application (interne à FireDAC). L'application va lire/écrire ce flux. Un flux interne est un wrapper d'objet fin pour une API de flux de valeurs BLOB de SGBD. C'est la raison pour laquelle les flux internes peuvent ne pas être pris en charge pour une BD si celle-ci n'a pas d'API pour le flux de valeurs BLOB, ou peuvent avoir une fonctionnalité limitée, par exemple des méthodes Seek / Position / Size non fonctionnelles, si la BD n'a pas d'API pour ces opérations. Pour plus de détails, reportez-vous à "Pilotes pris en charge".

Les opérations de flux interne nécessitent :

  • En premier lieu, l'exécution de la commande SQL. Le flux interne peut n'être accessible qu'après l'exécution.
  • D'être effectuées à l'intérieur d'une transaction explicite. Cette exigence est valable pour la plupart des API de BD.
  • De libérer une référence au flux interne dès que possible. Cela est dû au fait que certaines opérations, comme Commit, Unprepare ou CloseStreams peuvent libérer l'objet de flux interne.
  • D'utiliser des variables explicites pour les flux internes sur les compilateurs qui utilisent le comptage automatique de références (voir le code ci-dessous).

Pour utiliser le flux interne, l'application doit :

  • Démarrer une transaction ;
  • Définir le paramètre DataType sur ftStream.
  • Définir le paramètre StreamMode sur le mode de flux interne requis :
    • smOpenRead - pour lire la valeur BLOB de la BD ;
    • smOpenWrite - pour écrire la valeur BLOB de la BD ;
    • smOpenReadWrite - pour lire et écrire la valeur BLOB de la BD.
  • Facultativement, définir le paramètre ParamType sur le mode de paramètre requis. Notez que, contrairement au flux externe, ParamType influence l'initialisation de la référence de flux interne, et seul le paramètre StreamMode influence le mode d'ouverture de flux.
  • Facultativement, définir le paramètre FDDataType sur l'un des types de données BLOB, comme dtHBlob, dtBlob, dtHMemo ou dtWideHMemo. La valeur par défaut est ftBlob ou ftOraBlob, quand FDDataType n'est pas défini.
  • Exécuter la commande SQL. Cela renvoie la référence de flux interne ;
  • Lire/écrire la référence de flux interne ;
  • Facultativement, définir la méthode CloseStreams de l'ensemble de données ou de la commande pour vider les tampons des API de BD et fermer les flux internes. Cette opération est obligatoire pour les pilotes basés sur ODBC, InterBase et Firebird. Pour les autres pilotes, elle n'a aucun effet ;
  • Finir la transaction.


Par exemple :

FDConnection1.StartTransaction;
try
  FDQuery1.SQL.Text := 'INSERT INTO tab (blobdata) VALUES (:blobdata)';
  FDQuery1.Params[0].DataType := ftStream;
  FDQuery1.Params[0].StreamMode := smOpenWrite;
  FDQuery1.ExecSQL;
  oStr := TFileStream.Create('data.bin', fmOpenRead);
  try
    // Database receives a copy of the original stream
    {$IFDEF AUTOREFCOUNT}
      oInt := FDQuery.Params[0].AsStream;
      oInt.CopyFrom(oStr, -1);
      oInt := nil;   
    {$ELSE}
      FDQuery1.Params[0].AsStream.CopyFrom(oStr, -1);
    {$ENDIF}
  finally
    // The user is responsible for freeing the original stream 
    oStr.Free;
  end;
  FDQuery1.CloseStreams;
  FDConnection1.Commit;
except
  FDConnection1.Rollback;
  raise;
end;

FILESTREAM de SQL Server

La prise en charge de la fonctionnalité FILESTREAM de SQL Server est un cas particulier de flux interne. Pour des détails sur la configuration du serveur, veuillez lire la documentation (EN) relative à FILESTREAM de SQL Server.

Pour la DDL de la table, "data" est une colonne FILESTREAM et "rowguid" est une colonne rowguidcol. Une table avec une colonne FILESTREAM doit avoir une colonne rowguidcol pour identifier les flux.

create table FSTab (
  id int IDENTITY(1,1) NOT NULL Primary Key,
  name varchar(100) NOT NULL,
  data varbinary(max) filestream NULL,
  rowguid uniqueidentifier NOT NULL rowguidcol unique DEFAULT (newid())
)

Pour la commande SQL qui récupère les données, la colonne "data" est exclue de la liste SELECT, sinon le contenu FILESTREAM sera transféré "par valeur" au lieu d'utiliser le flux FILESTREAM. Utilisez plutôt la commande SQL avec un paramètre dont la valeur sera définie sur "data.PathName()" côté serveur.

select :p = data.PathName() from FSTab where id = :id

Pour utiliser le flux FILESTREAM dans FireDAC

  1. Définissez les paramètres suivants :
    • DataType sur l'une des valeurs suivantes :
      • ftBlob (pour travailler avec un flux externe ou transférer une valeur BLOB "par valeur") ;
      • ftStream (pour renvoyer un flux FILESTREAM interne) ;
    • FDDataType sur dtHBFile ;
    • ParamType sur ptOutput ;
    • StreamMode sur l'une des valeurs suivantes :
      • smOpenWrite (pour écrire vers FILESTREAM) ;
      • smOpenRead (pour lire depuis FILESTREAM) ;
      • smOpenReadWrite (pour lire/écrire depuis FILESTREAM) ;
  2. Démarrez une transaction.
  3. Exécutez une commande SQL renvoyant un PathName() dans le paramètre, qui effectuera le transfert de flux de valeurs BLOB. Les définitions ci-dessus sont une indication particulière du fait que l'application va utiliser le flux interne pour ce paramètre.
  4. Terminez la transaction.

Par exemple :

FDConnection1.StartTransaction;
try
  FDQuery.SQL.Text := 'select :p = data.PathName() from FSTab where id = :id';
  FDQuery.Params[0].DataType := ftStream;
  FDQuery.Params[0].FDDataType := dtHBFile;
  FDQuery.Params[0].ParamType := ptOutput;
  FDQuery.Params[0].StreamMode := smOpenRead;
  FDQuery.Params[1].AsInteger := 123;
  FDQuery.OpenOrExecute;
  // TFDParam.AsStream returns reference to internal low-level stream
  FDQuery.Params[0].AsStream.Read(Buffer, Length(Buffer));
  FDConnection1.Commit;
except
  FDConnection1.Rollback;
  raise;
end;

Pilotes pris en charge

Pilote Flux externe Flux interne

Advantage

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams. Avant d'écrire vers un flux, paramétrez le flux pour une longueur de flux complet.

DataSnap

Pris en charge.

Pris en charge.

DB2

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams.

Informix

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams.

InterBase

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams.

Firebird

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams.

MS Access

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams.

MS SQL Server

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams pour les types de données non FILESTREAM. La fonctionnalité FILESTREAM requiert une gestion spéciale.

MySQL

Pris en charge. Définissez Datatype sur ftBlob.

Non pris en charge.

ODBC

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams.

Oracle

Pris en charge. Définissez Datatype sur ftOraBlob ou ftOraClob.

Pris en charge. Définissez Datatype sur ftOraBlob ou ftOraClob. Requiert l'initialisation spéciale d'un champ BLOB/CLOB à l'insertion :

INSERT INTO tab (blobdata) VALUES (EMPTY_BLOB()) RETURNING blobdata {into :blobdata}

PostgreSQL

Pris en charge.

Pris en charge. Définissez le paramètre de connexion OidAsBlob sur Yes.

SQLite

Pris en charge.

Non pris en charge.

SQL Anywhere

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams.

Base de données Teradata

Pris en charge.

Pris en charge. Requiert un appel à CloseStreams.

Voir aussi

Exemples