Partager via


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

Les applications qui utilisent SqlOpenFilestream() pour ouvrir des handles de fichiers Win32 afin de 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 commune. Cela inclut Transact-SQL ou les requêtes MARS qui prennent beaucoup de temps pour terminer l’exécution. Les applications doivent être soigneusement conçues pour é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 savoir si l'opération d'ouverture travaille avec des instructions DDL, des instructions DML, récupère des données ou gère 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.

Transact-SQL instructions Ouvert pour 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és et échouent en raison d'un délai d'attente.
Instructions DML qui fonctionnent avec les données stockées dans la base de données, telles que UPDATE, DELETE et INSERT. Autorisé Refusé
Sélectionner Autorisé Autorisé
Valider la transaction Nié* Nié*.
ENREGISTRER LA TRANSACTION Nié* Nié*
RETOUR EN ARRIÈRE Autorisé* Autorisé*

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

Exemples

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

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

L’exemple suivant montre l’effet de l’ouverture d’un fichier uniquement pour l’accès 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 OBJET BLOB FILESTREAM pour l’accès en lecture

L’exemple suivant montre l’effet de l’ouverture d’un fichier uniquement pour l’accès 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, la règle la plus restrictive est utilisée. L’exemple suivant ouvre deux fichiers. Le premier fichier est ouvert pour la lecture et la seconde pour l’écriture. Les instructions DML sont 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 la fermeture d’un curseur

L’exemple suivant montre comment un curseur d’instruction qui n’est pas fermé peut empêcher OpenSqlFilestream() l’ouverture de l’objet 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 aux données FILESTREAM avec OpenSqlFilestream
Utilisation de MARS (Multiple Active Result Sets)