Vermeiden von Konflikten mit Datenbankvorgängen in FILESTREAM-Anwendungen

Gilt für:SQL Server

Anwendungen, die SqlOpenFilestream() zum Öffnen von Win32-Dateihandles zum Lesen oder Schreiben von FILESTREAM-BLOB-Daten verwenden, können Konfliktfehler mit Transact-SQL-Anweisungen auftreten, die in einer gemeinsamen Transaktion verwaltet werden. Dazu gehören Transact-SQL- oder MARS-Abfragen, die eine lange Zeit in Anspruch nehmen, um die Ausführung abzuschließen. Anwendungen müssen sorgfältig entworfen werden, wenn diese Art von Konflikten vermieden werden soll.

Wenn SQL Server-Datenbankmodul oder -Anwendungen versuchen, FILESTREAM BLOBs zu öffnen, überprüft das Datenbankmodul den zugeordneten Transaktionskontext. Das Datenbankmodul ermöglicht oder verweigert die Anforderung basierend darauf, ob der geöffnete Vorgang mit DDL-Anweisungen, DML-Anweisungen, Abrufen von Daten oder Verwalten von Transaktionen arbeitet. Die folgende Tabelle zeigt, wie das Datenbankmodul bestimmt, ob eine Transact-SQL-Anweisung basierend auf dem Typ der in der Transaktion geöffneten Dateien 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
AUSWÄHLEN 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 ungültig. 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)