次の方法で共有


FILESTREAM アプリケーションでのデータベース操作との競合を回避する

SqlOpenFilestream() を使用して WIN32 ファイル ハンドルを開き、FILESTREAM BLOB データの読み取りまたは書き込みを行うアプリケーションでは、一般的なトランザクションで管理されている 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 ステートメント。 許可 拒否する
選択する 許可 許可
トランザクションをコミット 拒否* 拒否*。
トランザクションの保存 拒否* 拒否*
ロールバック 許可* 許可*

* トランザクションが取り消され、トランザクション コンテキストのオープン ハンドルが無効になります。 アプリケーションは、開いているすべてのハンドルを閉じる必要があります。

例示

次の例は、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 ファイルを開いたり閉じたりする

複数のファイルが開いている場合は、最も制限の厳しい規則が使用されます。 次の例では、2 つのファイルを開きます。 最初のファイルは読み取り用に開き、2 番目のファイルは書き込み用に開かれます。 DML ステートメントは、2 番目のファイルが開かれるまで拒否されます。

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) の使用