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

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

Lorsque Moteur de base de données SQL Server ou des applications essaient d'ouvrir des 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 demande selon que l'opération en cours fonctionne avec des instructions DDL, des instructions DML, la récupération de données ou la gestion de transactions. Le tableau suivant indique comment le Moteur de base de données détermine si une instruction Transact-SQL sera autorisée ou refusée selon les types de fichiers qui sont ouverts pendant 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ées

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.

Allowed

Denied

SELECT

Allowed

Allowed

COMMIT TRANSACTION

Denied*

Denied*.

SAVE TRANSACTION

Denied*

Denied*

ROLLBACK

Allowed*

Allowed*

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

Exemples

Les exemples suivants illustrent comment les instructions Transact-SQL et l'accès FILESTREAM Win32 peut provoquer 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

Référence

Accéder à des données FILESTREAM avec OpenSqlFilestream

Concepts

Utilisation de MARS (Multiple Active Result Sets)