Избегание конфликтов в операциях баз данных в приложениях FILESTREAM
Область применения: SQL Server
Приложения, использующие SqlOpenFilestream() для открытия дескрипторов Файлов Win32 для чтения или записи данных BLOB FILESTREAM, могут столкнуться с конфликтными ошибками с инструкциями Transact-SQL, управляемыми в обычной транзакции. К ним относятся запросы Transact-SQL или MARS, которые занимают много времени для завершения выполнения. При разработке приложений надо уделить особое внимание предотвращению данных типов конфликтов.
Когда SQL Server ядро СУБД или приложения пытаются открыть BLOB-объекты FILESTREAM, ядро СУБД проверяет связанный контекст транзакции. Ядро СУБД разрешает или запрещает запрос на основе того, работает ли открытая операция с операторами DDL, операторами DML, получением данных или управлением транзакциями. В следующей таблице показано, как ядро СУБД определяет, будет ли инструкция Transact-SQL разрешена или запрещена в зависимости от типа файлов, открытых в транзакции.
Инструкции Transact-SQL | Открыты для чтения | Открыты для записи |
---|---|---|
Инструкции DDL, работающие с метаданными базы данных, например CREATE TABLE, CREATE INDEX, DROP TABLE и ALTER TABLE. | Допустимо | Заблокированы и завершаются со сбоем по истечении времени ожидания. |
Инструкции DML, работающие с данными, хранящимися в базе данных, например UPDATE, DELETE и INSERT. | Допустимо | Отклонено |
SELECT | Допустимо | Допустимо |
COMMIT TRANSACTION | Запрещены* | Запрещены* |
SAVE TRANSACTION | Запрещены* | Запрещены* |
ROLLBACK | Разрешено* | Разрешено* |
* Транзакция отменена, а открытые дескрипторы для контекста транзакции недействительны. Приложение должно закрыть все открытые дескрипторы.
Примеры
В следующих примерах показано, как инструкции Transact-SQL и доступ к FILESTREAM Win32 могут вызвать конфликты.
А. Открытие объекта FILESTREAM BLOB с доступом на запись
В следующем примере показывается эффект от открытия файла с доступом только на запись.
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. Открытие объекта FILESTREAM BLOB с доступом на считывание
В следующем примере показывается эффект от открытия файла с доступом только на считывание.
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. Открытие и закрытие нескольких файлов FILESTREAM BLOB
Если открыто несколько файлов, то используется правило с наибольшими ограничениями. В следующем примере открываются два файла. Первый файл открывается для чтения, а второй — для записи. Инструкции DML будут запрещены, пока не будет открыт второй файл.
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. Сбой при закрытии курсора
В следующем примере показывается, как незакрытый курсор инструкции может помешать функции OpenSqlFilestream()
открыть объект BLOB для доступа на запись.
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.
См. также
Доступ к данным FILESTREAM с OpenSqlFilestream
Использование множественных активных результирующих наборов (MARS)