Éviter les conflits avec les opérations de base de données dans les applications FILESTREAM

S’applique à :SQL Server

Les applications qui utilisent SqlOpenFilestream() pour ouvrir des handles de fichiers Win32 pour lire ou écrire des données BLOB FILESTREAM peuvent rencontrer des erreurs de conflit avec des instructions Transact-SQL gérées dans une transaction courante. Cela inclut les requêtes Transact-SQL ou MARS qui prennent beaucoup de temps pour terminer l’exécution. Les applications doivent être conçues avec soin afin de mieux éviter ces types de conflits.

Lorsque les applications ou moteur de base de données SQL Server essaient d’ouvrir des objets blob FILESTREAM, le moteur de base de données vérifie le contexte de transaction associé. Le moteur de base de données autorise ou refuse la requête en fonction de l’utilisation des instructions DDL, des instructions DML, de la récupération de données ou de la gestion des transactions. Le tableau suivant montre comment le moteur de base de données détermine si une instruction Transact-SQL sera autorisée ou refusée en fonction du type de fichiers ouverts dans la transaction.

instructions Transact-SQL Ouvert pour la lecture Ouvert pour l'écriture
Instructions DDL qui fonctionnent avec des métadonnées de base de données, telles que CREATE TABLE, CREATE INDEX, DROP TABLE et ALTER TABLE. Autorisé Sont bloquées et échouent à la suite d'un délai d'expiration.
Instructions DML qui fonctionnent avec les données qui sont stockées dans la base de données, telles qu'UPDATE, DELETE et INSERT. Autorisé Refusé
SELECT Autorisé Autorisé
COMMIT TRANSACTION Refusées* Refusées*
SAVE TRANSACTION Refusées* Refusées*
ROLLBACK Autorisées* Autorisées*

* La transaction est annulée et les handles ouverts pour le contexte de transaction sont invalidés. L'application doit fermer tous les descripteurs ouverts.

Examples

Les exemples suivants montrent comment les instructions Transact-SQL et l’accès FILESTREAM Win32 peuvent entraîner des conflits.

A. Ouverture d'un BLOB FILESTREAM pour un accès en écriture

L'exemple suivant montre l'effet d'ouverture d'un fichier pour un accès uniquement en écriture.

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. Ouverture d'un BLOB FILESTREAM pour un accès en lecture

L'exemple suivant montre l'effet d'ouverture d'un fichier pour un accès uniquement en lecture.

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. Ouverture et fermeture de plusieurs fichiers BLOB FILESTREAM

Si plusieurs fichiers sont ouverts, c'est la règle la plus restrictive qui est utilisée. L'exemple suivant ouvre deux fichiers. Le premier fichier est ouvert pour la lecture et le second pour l'écriture. Les instructions DML seront refusées jusqu'à ce que le deuxième fichier soit ouvert.

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. Échec de fermeture d'un curseur

L'exemple suivant montre comment un curseur d'instruction qui n'est pas fermé peut empêcher OpenSqlFilestream() d'ouvrir le BLOB pour l'accès en écriture.

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.  

Voir aussi

Accéder à des données FILESTREAM avec OpenSqlFilestream
Utilisation de MARS (Multiple Active Result Sets)