É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 pour la lecture ou l’écriture de données BLOB FILESTREAM peuvent rencontrer des erreurs de conflit avec les 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 Moteur de base de données SQL Server ou des applications essaient d’ouvrir des FILESTREAM BLOB, le Moteur de base de données vérifie le contexte de transaction associé. 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 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ée |
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 descripteurs ouverts pour le contexte de transaction sont invalidés. L'application doit fermer tous les descripteurs ouverts.
Exemples
Les exemples suivants montrent comment les instructions Transact-SQL et l’accès FILESTREAM Win32 peuvent provoquer des conflits.
R. 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)