Conflitti tra Win32 e Transact-SQL
Le applicazioni che utilizzano SqlOpenFilestream() per aprire gli handle di file Win32 per la lettura o la scrittura di dati BLOB FILESTREAM possono entrare in conflitto con le istruzioni Transact-SQL gestite in una transazione comune. Sono incluse le query Transact-SQL o MARS la cui esecuzione richiede molto tempo. È necessario progettare con attenzione le applicazioni per evitare questi tipi di conflitti.
Quando il Motore di database di SQL Server o le applicazioni tentano di aprire dati BLOB FILESTREAM, il Motore di database controlla il contesto di transazione associato. Il Motore di database consente o nega la richiesta a seconda che l'operazione di apertura funzioni o meno con le istruzioni DDL, le istruzioni DML, il recupero dei dati o la gestione delle transazioni. Nella tabella seguente viene illustrato il modo in cui il Motore di database determina se un 'istruzione Transact-SQL verrà consentita o negata in base al tipo di file aperti nella transazione.
Istruzioni Transact-SQL |
Aperte per l'accesso in lettura |
Aperte per l'accesso in scrittura |
---|---|---|
Istruzioni DDL che funzionano con i metadati del database, ad esempio CREATE TABLE, CREATE INDEX, DROP TABLE e ALTER TABLE. |
Consentite |
Bloccate ed errore di timeout. |
Istruzioni DML che funzionano con i dati archiviati nel database, ad esempio UPDATE, DELETE e INSERT. |
Consentite |
Negate |
SELECT |
Consentite |
Consentite |
COMMIT TRANSACTION |
Negate* |
Negate* |
SAVE TRANSACTION |
Negate* |
Negate* |
ROLLBACK |
Consentite* |
Consentite* |
* La transazione viene annullata e gli handle aperti per il contesto di transazione vengono invalidati. L'applicazione deve chiudere tutti gli handle aperti.
Esempi
Negli esempi seguenti viene illustrato come le istruzioni Transact-SQL e l'accesso Win32 FILESTREAM possano creare conflitti.
A. Apertura di dati BLOB FILESTREAM per l'accesso in scrittura
Nell'esempio seguente viene mostrato l'effetto dell'apertura di un file per il solo accesso in scrittura.
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. Apertura di dati BLOB FILESTREAM per l'accesso in lettura
Nell'esempio seguente viene mostrato l'effetto dell'apertura di un file per il solo accesso in lettura.
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. Apertura e chiusura di più file BLOB FILESTREAM
Se sono aperti più file, viene utilizzata la regola più restrittiva. Nell'esempio seguente vengono aperti due file. Il primo file è aperto in lettura, il secondo in scrittura. Le istruzioni DML rimarranno negate finché non viene aperto il secondo file.
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. Chiusura non riuscita di un cursore
Nell'esempio seguente viene illustrato come un cursore dell'istruzione non chiuso possa impedire a OpenSqlFilestream() di aprire i dati BLOB per l'accesso in scrittura.
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.
Vedere anche