다음을 통해 공유


FILESTREAM 애플리케이션에서 데이터베이스 작업과의 충돌 방지

적용 대상: SQL Server

FILESTREAM BLOB 데이터를 읽거나 쓰기 위해 SqlOpenFilestream()을 사용하여 Win32 파일 핸들을 여는 애플리케이션은 공통된 트랜잭션에서 관리되는 Transact-SQL 문과의 충돌 오류가 발생할 수 있습니다. 여기에는 실행을 완료하는 데 시간이 오래 걸리는 Transact-SQL 또는 MARS 쿼리가 포함됩니다. 이러한 유형의 충돌을 방지하기 위해 애플리케이션을 신중하게 설계해야 합니다.

SQL Server 데이터베이스 엔진 또는 애플리케이션이 FILESTREAM BLOB을 열려고 하면 데이터베이스 엔진 연결된 트랜잭션 컨텍스트를 확인합니다. 데이터베이스 엔진 열린 작업이 DDL 문, DML 문, 데이터 검색 또는 트랜잭션 관리와 함께 작동하는지 여부에 따라 요청을 허용하거나 거부합니다. 다음 표에서는 데이터베이스 엔진 트랜잭션에 열려 있는 파일 형식에 따라 Transact-SQL 문을 허용할지 또는 거부할지를 결정하는 방법을 보여 줍니다.

TRANSACT-SQL 문 읽기를 위해 열림 쓰기 위해 열렸습니다.
CREATE TABLE, CREATE INDEX, DROP TABLE 및 ALTER TABLE과 같은 데이터베이스 메타데이터와 함께 작동하는 DDL 문입니다. 허용됨 차단되고 시간 초과 오류가 발생합니다.
데이터베이스에 저장된 데이터(예: UPDATE, DELETE 및 INSERT)와 함께 작동하는 DML 문입니다. 허용됨 거부됨
SELECT 허용됨 허용됨
COMMIT TRANSACTION 거부됨* 거부됨*.
SAVE TRANSACTION 거부됨* 거부됨*
롤백 허용됨* 허용됨*

* 트랜잭션이 취소되고 트랜잭션 컨텍스트의 열린 핸들이 무효화됩니다. 애플리케이션은 열려 있는 모든 핸들을 닫아야 합니다.

예제

다음 예제에서는 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.  

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.  

참고 항목

OpenSqlFilestream을 사용하여 FILESTREAM 데이터 액세스
MARS(다중 활성 결과 집합) 사용