Unterstützung für das Blob-Streaming in FireDAC

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Arbeiten mit Anweisungen (FireDAC)


Die Technik BLOB-Streaming implementiert BLOB-Parameterwerte, die von/zu einer Datenbank gestreamt werden. Dadurch wird die Übertragung von BLOB-Werten "per Referenz" in Gegensatz zur Übertragung von BLOB-Werten "per Wert" ermöglicht. Vorteile dieser Technik:

  • Die Verwendung des clientseitigen Speichers wird minimiert; bei der Übertragung "per Wert" wird zusätzlicher Speicher von der 3- bis 4-fachen Größe der Größe des BLOB-Wertes benötigt.
  • Die Leistung ist 1,5 bis 2 mal besser als die Leistung bei der Übertragung "per Wert".
  • BLOB-Werte können "blockweise" aktualisiert werden, bei der Übertragung "per Wert" kann ein BLOB nur vollständig aktualisiert werden.

Nachteile:

  • Die Datentyp-/Codierungstransformation wird für die meisten Datenbanken nicht durchgeführt.
  • Wird nur für Befehlsparameter, nicht für Spalten unterstützt.

Folgende APIs übertragen BLOB-Werte "per Wert":

Die BLOB-Streaming-API umfasst:

Verwendung

FireDAC bietet zwei Arten von BLOB-Streaming: Externe Streams und Interne Streams.

Externe Streams

Ein externer Stream wird von der Anwendung für FireDAC (extern für FireDAC) bereitgestellt. FireDAC liest/schreibt diesen Stream. Externe Streams werden für alle DBs unterstützt.

Um das externe Streaming zu verwenden, muss die Anwendung:

  • Optional den Parameter DataType auf einen der BLOB-Datentypen, wie ftOraBlob, ftBlob, ftMemo, ftWideMemo, setzen. Wenn dieser Parameter nicht gesetzt ist, wird bei der nächsten Zuweisung der Eigenschaft AsStream der Datentyp des Parameters implizit auf ftStream gesetzt.
  • Optional den Parameter ParamType festlegen. Damit wird der Übertragungsmodus angegeben:
    • ptInput – der Stream wird aus einem bzw. in einen DB-BLOB-Wert gelesen/geschrieben.
    • ptOutput – ein DB-BLOB-Wert wird aus einem bzw. in einen Stream gelesen/geschrieben.
  • Der Parametereigenschaft AsStream eine Stream-Referenz zuweisen. In diesem Fall wird FireDAC zum Eigentümer der Stream-Referenz. Das Objekt wird nach dem Aufheben der Vorbereitung der Abfrage oder nach der nächsten Wertzuweisung freigegeben. Alternativ können Anwendungen mit der Parametermethode SetStream die Eigentümerschaft steuern. Der Stream wird ab der aktuellen Stream-Position verwendet.
  • Die SQL-Anweisung ausführen.

Zum Beispiel:

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;

Interne Streams

Ein interner Stream wird von FireDAC für die Anwendung (intern für FireDAC) bereitgestellt. Die Anwendung liest/schreibt diesen Stream. Ein interner Stream ist ein schlanker Objekt-Wrapper für eine BLOB-Streaming-API des DBMS. Daher werden interne Streams möglicherweise nicht für eine DB unterstützt, wenn sie über keine API für das BLOB-Streaming verfügt, oder bieten nur eine begrenzte Funktionalität, z. B. nicht funktionierende Seek-/Position-/Size-Methoden, wenn die DB keine API für diese Vorgänge bereitstellt. Einzelheiten finden Sie unter "Unterstützte Treiber".

Für die internen Stream-Vorgänge ist Folgendes erforderlich:

  • Die SQL-Anweisung muss zuerst ausgeführt werden. Auf den internen Stream kann möglicherweise nur nach der Ausführung zugegriffen werden.
  • Sie müssen innerhalb einer expliziten Transaktion ausgeführt werden. Diese Anforderung gilt für die meisten DB-APIs.
  • Eine Referenz auf den internen Stream muss so früh wie möglich freigegeben werden. Und zwar weil einige Vorgänge, wie Commit, Unprepare oder CloseStreams das interne Stream-Objekt freigeben könnten.
  • Verwenden Sie eindeutige Variablen für interne Streams in Compilern, die Automatische Referenzzählung verwenden (siehe unten dargestellten Code).

Um das interne Streaming zu verwenden, muss die Anwendung:

  • Eine Transaktion starten.
  • Den Parameter DataType auf ftStream setzen.
  • Den Parameter StreamMode auf den erforderlichen internen Stream-Modus setzen:
    • smOpenRead - zum Lesen des DB-BLOB-Werts
    • smOpenWrite - zum Schreiben des DB-BLOB-Werts;
    • smOpenReadWrite - zum Lesen und Schreiben des DB-BLOB-Werts
  • Optional den Parameter ParamType auf den erforderlichen Parametermodus setzen. Im Gegensatz zum externen Streaming wirkt sich ParamType auf die Initialisierung der internen Stream-Referenz aus, und nur der Parameter StreamMode wirkt sich auf den Öffnungsmodus des Streams aus.
  • Optional den Parameter FDDataType auf einen der BLOB-Datentypen, wie dtHBlob, dtBlob, dtHMemo oder dtWideHMemo setzen. Der Wert ist standardmäßig ftBlob oder ftOraBlob, wenn FDDataType nicht gesetzt ist.
  • Die SQL-Anweisung ausführen. Dadurch wird die interne Stream-Referenz zurückgegeben.
  • Die interne Stream-Referenz lesen/schreiben.
  • Optional die Datenmengen- oder die Befehlsmethode CloseStreams aufrufen, um die DB-API-Puffer zu leeren und die internen Streams zu schließen. Dies ist für ODBC-basierte Treiber obligatorisch, für andere Treiber wird nichts ausgeführt.
  • Die Transaktion beenden.


Zum Beispiel:

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;

SQL Server FILESTREAM

Die Unterstützung von SQL Sever FILESTREAM ist ein Sonderfall des internen Streaming. Einzelheiten zur Konfiguration finden Sie in der Dokumentation zu SQL Server FILESTREAM.

In der Tabellen-DDL ist "data" eine FILESTREAM-Spalte und "rowguid" eine rowguidcol-Spalte. Eine Tabelle mit einer FILESTREAM -Spalte muss zum Identifizieren von Streams über eine rowguidcol-Spalte verfügen.

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())
)

Bei der SQL-Anweisung, die die Daten abruft, wird die Spalte "data" aus der SELECT-Liste ausgeschlossen, weil dadurch der FILESTREAM-Inhalt "per Wert" anstatt mit dem FILESTREAM-Streaming übertragen wird. Verwenden Sie stattdessen eine SQL-Anweisung mit einem Parameter, dessen Wert auf der Serverseite auf "data.PathName()" gesetzt wird.

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

So verwenden Sie das FILESTREAM-Streaming in FireDAC:

  1. Legen Sie die folgenden Parameter fest:
    • DataType kann folgende Werte annehmen:
      • ftBlob (für externe Streams oder zum Übertragen eines BLOB-Wertes "per Wert");
      • ftStream (für die Rückgabe eines internen FILESTREAM-Streams);
    • FDDataType auf dtHBFile;
    • ParamType auf ptOutput;
    • StreamMode kann folgende Werte annehmen:
      • smOpenWrite (zum Schreiben in FILESTREAM);
      • smOpenRead (zum Lesen aus FILESTREAM);
      • smOpenReadWrite (zum Lesen aus/Schreiben in FILESTREAM);
  2. Starten Sie eine Transaktion.
  3. Führen Sie eine SQL-Anweisung aus, die einen PathName() im Parameter zurückgibt, anhand dessen das BLOB-Streaming durchgeführt wird. Die obigen Einstellungen sind ein Zeichen dafür, dass die Anwendung das interne Streaming für diesen Parameter verwendet.
  4. Beenden Sie die Transaktion.

Zum Beispiel:

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;

Unterstützte Treiber

Treiber Externes Streaming Internes Streaming

Advantage

Unterstützt.

Unterstützt.

DataSnap

Unterstützt.

Unterstützt.

DB2

Unterstützt.

Unterstützt. Aufruf von CloseStreams erforderlich.

Informix

Unterstützt.

Unterstützt. Aufruf von CloseStreams erforderlich.

InterBase

Unterstützt.

Unterstützt. Aufruf von CloseStreams erforderlich.

Firebird

Unterstützt.

Unterstützt. Aufruf von CloseStreams erforderlich.

MS Access

Unterstützt.

Unterstützt. Aufruf von CloseStreams erforderlich.

MS SQL Server

Unterstützt.

Unterstützt. Erfordert den Aufruf von CloseStreams für Nicht-FILESTREAM-Datentypen. Für FILESTREAM ist eine Sonderbehandlung erforderlich.

MySQL

Unterstützt. Setzen Sie Datatype auf ftBlob.

Nicht unterstützt.

ODBC

Unterstützt.

Unterstützt. Aufruf von CloseStreams erforderlich.

Oracle

Unterstützt. Setzen Sie Datatype auf ftOraBlob oder ftOraClob.

Unterstützt. Setzen Sie Datatype auf ftOraBlob oder ftOraClob. Erfordert eine besondere Initialisierung eines BLOB/CLOB-Feldes beim Einfügen:

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

PostgreSQL

Unterstützt.

Unterstützt. Setzen Sie den Verbindungsparameter OidAsBlob auf Yes.

SQLite

Unterstützt.

Nicht unterstützt.

SQL Anywhere

Unterstützt.

Unterstützt. Aufruf von CloseStreams erforderlich.

Teradata Database

Unterstützt.

Unterstützt. Aufruf von CloseStreams erforderlich.

Siehe auch

Beispiele