Vermeiden von Konflikten mit Datenbankvorgängen in FILESTREAM-Anwendungen

Bei Anwendungen, die SqlOpenFilestream() zum Öffnen von Win32-Dateihandles zum Lesen oder Schreiben von FILESTREAM BLOB-Daten verwenden, können Konflikte mit Transact-SQL-Anweisungen auftreten, die in einer allgemeinen Transaktion verwaltet werden. Dies umfasst Transact-SQL- oder MARS-Abfragen, die lange dauern, bis die Ausführung abgeschlossen ist. Anwendungen müssen sorgfältig entworfen werden, wenn diese Art von Konflikten vermieden werden soll.

Wenn die SQL Server-Datenbank-Engine oder Anwendungen versuchen, FILESTREAM-BLOBs zu öffnen, überprüft die Datenbank-Engine den zugeordneten Transaktionskontext. Die Datenbank-Engine lässt die Anforderung zu bzw. verweigert sie in Abhängigkeit davon, ob der geöffnete Vorgang mit DDL-Anweisungen oder DML-Anweisungen arbeitet, Daten abruft oder Transaktionen verwaltet. Die folgende Tabelle zeigt, wie datenbank-Engine anhand des Typs der in der Transaktion geöffneten Dateien bestimmt, ob eine Transact-SQL-Anweisung zulässig oder verweigert wird.

Transact-SQL-Anweisungen Geöffnet zum Lesen Geöffnet zum Schreiben
DDL-Anweisungen, die mit Datenbankmetadaten arbeiten, z. B. CREATE TABLE, CREATE INDEX, DROP TABLE und ALTER TABLE. Zulässig Werden blockiert und schlagen mit einem Timeout fehl.
DML-Anweisungen, die mit den Daten arbeiten, die in der Datenbank gespeichert sind, z. B. UPDATE, DELETE und INSERT. Zulässig Verweigert
SELECT Zulässig Zulässig
COMMIT TRANSACTION Verweigert* Verweigert*
SAVE TRANSACTION Verweigert* Verweigert*
ROLLBACK Zulässig* Zulässig*

* Die Transaktion wird abgebrochen, und geöffnete Handles für den Transaktionskontext werden für ungültig erklärt. Die Anwendung muss alle geöffneten Handles schließen.

Beispiele

Die folgenden Beispiele zeigen, wie Transact-SQL-Anweisungen und FILESTREAM Win32-Zugriff Konflikte verursachen können.

A. Öffnen eines FILESTREAM-BLOB für Schreibzugriff

Das folgende Beispiel zeigt die Auswirkung des Öffnens einer Datei nur für den Schreibzugriff.

dstHandle =  OpenSqlFilestream(dstFilePath, Write, 0,  
    transactionToken, cbTransactionToken, 0);  
  
//Write some date to the FILESTREAM BLOB.  
WriteFile(dstHandle, updateData, ...);  
  
//DDL statements will be denied.  
//DML statements will be denied.  
//SELECT statements will be allowed. The FILESTREAM BLOB is  
//returned without the modifications that are made by  
//WriteFile(dstHandle, updateData, ...).  
CloseHandle(dstHandle);  
  
//DDL statements will be allowed.  
//DML statements will be allowed.  
//SELECT statements will be allowed. The FILESTREAM BLOB  
//is returned with the updateData applied.  

B. Öffnen eines FILESTREAM-BLOB für Lesezugriff

Das folgende Beispiel zeigt die Auswirkung des Öffnens einer Datei nur für den Lesezugriff.

dstHandle =  OpenSqlFilestream(dstFilePath, Read, 0,  
    transactionToken, cbTransactionToken, 0);  
//DDL statements will be denied.  
//DML statements will be allowed. Any changes that are  
//made to the FILESTREAM BLOB will not be returned until  
//the dstHandle is closed.  
//SELECT statements will be allowed.  
CloseHandle(dstHandle);  
  
//DDL statements will be allowed.  
//DML statements will be allowed.  
//SELECT statements will be allowed.  

C. Öffnen und Schließen von mehreren FILESTREAM-BLOB-Dateien

Wenn mehrere Dateien geöffnet sind, wird die restriktivste Regel verwendet. Im folgenden Beispiel werden zwei Dateien geöffnet. Die erste Datei wird für den Lesezugriff geöffnet, die zweite für den Schreibzugriff. DML-Anweisungen werden verweigert, bis die zweite Datei geöffnet wird.

dstHandle =  OpenSqlFilestream(dstFilePath, Read, 0,  
    transactionToken, cbTransactionToken, 0);  
//DDL statements will be denied.  
//DML statements will be allowed.  
//SELECT statements will be allowed.  
  
dstHandle1 =  OpenSqlFilestream(dstFilePath1, Write, 0,  
    transactionToken, cbTransactionToken, 0);  
  
//DDL statements will be denied.  
//DML statements will be denied.  
//SELECT statements will be allowed.  
  
//Close the read handle. The write handle is still open.  
CloseHandle(dstHandle);  
//DML statements are still denied because the write handle is open.  
  
//DDL statements will be denied.  
//DML statements will be denied.  
//SELECT statements will be allowed.  
  
CloseHandle(dstHandle1);  
//DDL statements will be allowed.  
//DML statements will be allowed.  
//SELECT statements will be allowed.  

D: Fehler beim Schließen eines Cursors

Das folgende Beispiel zeigt, wie ein nicht geschlossener Anweisungscursor verhindern kann, dass OpenSqlFilestream() den BLOB für den Schreibzugriff öffnen kann.

TCHAR *sqlDBQuery =  
TEXT("SELECT GET_FILESTREAM_TRANSACTION_CONTEXT(),")  
TEXT("Chart.PathName() FROM Archive.dbo.Records");  
  
//Execute a long-running Transact-SQL statement. Do not allow  
//the statement to complete before trying to  
//open the file.  
  
SQLExecDirect(hstmt, sqlDBQuery, SQL_NTS);  
  
//Before you call OpenSqlFilestream() any open files  
//that the Cursor the Transact-SQL statement is using  
// must be closed. In this example,  
//SQLCloseCursor(hstmt) is not called so that  
//the transaction will indicate that there is a file  
//open for reading. This will cause the call to  
//OpenSqlFilestream() to fail because the file is  
//still open.  
  
HANDLE srcHandle =  OpenSqlFilestream(srcFilePath,  
     Write, 0,  transactionToken,  cbTransactionToken,  0);  
  
//srcHandle will == INVALID_HANDLE_VALUE because the  
//cursor is still open.  

Weitere Informationen

ZUgreifen auf FILESTREAM-Daten mit OpenSqlFilestream
Verwenden von Multiple Active Result Sets (MARS)