Evitar conflictos con operaciones de base de datos en aplicaciones FILESTREAM

Se aplica a:SQL Server

Las aplicaciones que usan SqlOpenFilestream() para abrir identificadores de archivo Win32 para leer o escribir datos DE BLOB FILESTREAM pueden encontrar errores de conflicto con instrucciones Transact-SQL administradas en una transacción común. Esto incluye consultas transact-SQL o MARS que tardan mucho tiempo en finalizar la ejecución. Las aplicaciones deben diseñarse cuidadosamente para ayudar a evitar estos tipos de conflictos.

Cuando Motor de base de datos de SQL Server o las aplicaciones intentan abrir BLOB de FILESTREAM, Motor de base de datos comprueba el contexto de transacciones asociado. Motor de base de datos permite o deniega la solicitud en función de si la operación abierta opera con instrucciones DDL, instrucciones DML, la recuperación de los datos o la administración de las transacciones. En la tabla siguiente se muestra cómo determina el motor de base de datos si se permitirá o denegará una instrucción Transact-SQL en función del tipo de archivos abiertos en la transacción.

Instrucciones Transact-SQL Abierto para lectura Abierto para escritura
Instrucciones DDL que trabajan con los metadatos de la base de datos, como CREATE TABLE, CREATE INDEX, DROP TABLE y ALTER TABLE. Permitida Se bloquean y agotan el tiempo de espera con un error.
Instrucciones DML que trabajan con los datos que están almacenados en la base de datos, como UPDATE, DELETE e INSERT. Permitida Denegado
SELECT Permitida Permitida
COMMIT TRANSACTION Denegado* Denegado*
SAVE TRANSACTION Denegado* Denegado*
ROLLBACK Permitido* Permitido*

* La transacción se cancela y se invalidan los identificadores abiertos para el contexto de transacciones. La aplicación debe cerrar todos los identificadores abiertos.

Ejemplos

En los ejemplos siguientes se muestra cómo las instrucciones Transact-SQL y el acceso a FILESTREAM Win32 pueden causar conflictos.

A. Abrir un BLOB de FILESTREAM para acceso de escritura

En el ejemplo siguiente se muestra el efecto de abrir únicamente un archivo para acceso de escritura.

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. Abrir un BLOB de FILESTREAM para acceso de lectura

En el ejemplo siguiente se muestra el efecto de abrir únicamente un archivo para acceso de lectura.

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. Abrir y cerrar varios archivos BLOB de FILESTREAM

Si hay varios archivos abiertos, se usa la regla más restrictiva. En el ejemplo siguiente se abren dos archivos. El primero se abre durante la lectura y el segundo para la escritura. Se denegarán las instrucciones DML hasta que se abra el segundo archivo.

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. No se puede cerrar un cursor

El ejemplo siguiente muestra cómo un cursor de instrucción que no se cierra puede evitar que OpenSqlFilestream() abra el BLOB para acceso de escritura.

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.  

Consulte también

Obtener acceso a los datos FILESTREAM con OpenSqlFilestream
Utilizar conjuntos de resultados activos múltiples (MARS)