Избегание конфликтов в операциях баз данных в приложениях FILESTREAM
Приложения, использующие SqlOpenFilestream() для открытия дескрипторов файлов Win32 для чтения или записи данных BLOB-объектов FILESTREAM, могут столкнуться с конфликтами с инструкциями Transact-SQL, управляемыми в общей транзакции. К ним относятся запросы Transact-SQL или MARS, выполнение которым занимает много времени. При разработке приложений надо уделить особое внимание предотвращению данных типов конфликтов.
Если компонент Компонент SQL Server Database Engine или приложения пытаются открыть объекты FILESTREAM BLOB, то компонент Компонент Database Engine выполнит проверку контекста ассоциированной транзакции. Компонент Компонент Database Engine разрешит или запретит запрос в зависимости от того, работает ли операция открытия с инструкциями DDL, инструкциями DML, получает данные или управляет транзакциями. В следующей таблице показано, как компонент Компонент Database Engine определяет, будет ли инструкция 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 могут вызывать конфликты.
A. Открытие объекта 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.
Б. Открытие объекта 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.
В. Открытие и закрытие нескольких файлов 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.
Г. Сбой при закрытии курсора
В следующем примере показывается, как незакрытый курсор инструкции может помешать функции 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