どのような場合に <cflock scope="application"> を使用するのが適切ですか? または <cflock name="foo"> とは対照的に、それは同類ですか?
具体的には、CFLock を使用してアプリケーション、セッション、またはサーバー スコープ内の共有オブジェクトを保護することに関心がありますが、ColdFusion でのロックのさまざまな用途についても知りたいと思っています。
どのような場合に <cflock scope="application"> を使用するのが適切ですか? または <cflock name="foo"> とは対照的に、それは同類ですか?
具体的には、CFLock を使用してアプリケーション、セッション、またはサーバー スコープ内の共有オブジェクトを保護することに関心がありますが、ColdFusion でのロックのさまざまな用途についても知りたいと思っています。
アプリケーションスコープで変更できるものから読み書きするときに使用する必要があります。例えば:
<cfquery name="application.myData">
select * from myTable
</cfquery>
type="exclusive" でそれをロックしたいと思うでしょう。application.myData を使用する場合は常に、type="readonly" ロックが必要です。例外は、自身をロックする Application.cfc の OnApplicationStart メソッドです。同様に、セッション スコープとサーバー スコープで同じ戦略を使用します。
名前付きロックを使用すると、ロック戦略をより詳細に制御できます。コマンドを動的にロックする必要がある場合は、名前付きの cflock を使用します。例えば:
<cflock name="write_file_#session.user_type#" type="exclusive">
<cffile action="write" name="file_#session.user_type#" output="#content#" />
</cflock>
この例では、異なるタイプのユーザーが同時にファイルに書き込むことができますが、同じsession.user_typeを持つユーザーは互いに待機する必要があります。この cflock は、ファイル競合の問題を回避するのに役立ちます。
名前付きロックを使用するもう 1 つの理由は、現在の操作の範囲がわからない場合です。インスタンス化された CFC を使用している場合、インスタンス化されたスコープをどのように知ることができますか? 変数?セッション?応用?適切なカプセル化は、オブジェクトが伝えられたこと以外は何も知らないことを教えてくれます。CFC 内では、名前付きロックを使用して、ユース ケースに応じて、CFC にちなんで名前を付けるか、CFC と一意のインスタンス変数を付けます。
ここで他の提案に基づいて構築します。
正直に言うと、cf8 の出現と duplicate() でオブジェクトを複製できるようになったので、アプリケーション、セッション、またはサーバー スコープに書き込む場合にのみスコープ ロックを使用します (ところで、サーバー スコープへの書き込みは私の中では大したことではありません本)。
データを読み取る必要がある場合は、 duplicate() を使用してデータをローカル変数にディープコピーし、読み取りロックをすべて回避します。これにより、デッドロックが防止されます。
<cflock scope="application" timeout="5" type="exlusive">
<cfset application.data = {}>
<cfset application.data.firstname = "tony">
</cflock>
<cfset variables.firstname = duplicate(application.data.firstname)>
@Mr. ネイト氏は、競合状態が気になるときはいつでもロックを使用すると言いました。たとえば、セッションの初期化をロックしたいが、その後の読み取りはロックしたくない場合があります。同様に、アプリケーション スコープへの書き込みはロックしたいが、読み取りはロックしたくない場合があります。
スレッドセーフな共有変数スコープを導入したCF6以降、読み取りのロックはあまり役に立ちません。昔は、注意を怠ると、同じメモリ アドレスを同時に読み書きしていた可能性がありました。ただし、CF は Java を利用するようになったので、これは問題ではありません。
彼が示したように、名前付きロックは、ファイルの読み取り/書き込みなど、範囲が限定されていないものをロックするのに役立ちます。
名前付きロックを使用するのに適しているのは、データベース内の複数のテーブルを一度に更新するなど、「トランザクション」が一度に発生することを確認したい場合、または単に 2 人のユーザーが確実にアクセスされていることを確認したい場合です。一度に同じデータベース レコードを更新しない場合、または一度に複数のユーザーがアクセスしようとしている可能性があるサーバー上のファイルを読み書きする場合。
簡単に言えば、2 つのリクエストが同時に同じことを行おうとした場合に問題が発生する可能性がある状況が発生した場合はいつでも、その周りに名前付きロックを配置します (または、厳密にセッション、アプリケーション、またはサーバー スコープに関係する場合は、スコープ付きロック)。
Ben Nadel は、次のようなブログ エントリを投稿しました。
「私の見方では、CFLock の使用を要求するには、次の 2 つの条件を満たす必要があります。
- 共有リソースがアクセス中または更新中です。
- 負の結果をもたらす競合状態の可能性があるに違いありません。」
トランザクションの周りに名前付きロックを配置したり、内部にセッションまたはアプリケーション スコープのロックをネストしたりするなど、CFLOCK タグをネストすることもできますが、慎重に行ってください。ページのロックされたセクションを実行でき、ページのロックされたセクションへのすべてのリクエストは、タイムアウトになるまでブロックされる可能性があります。(ColdFusion のマニュアルでは、ネストされたロックのベスト プラクティスについて説明しています。)
通常、セッション、アプリケーション、およびサーバーの変数を Application.cfc の外で読み取ったり変更したりするときは常に、競合状態を防ぐために cflock を使用する必要があります。役に立つかもしれない記事は次のとおりです。
http://www.horwith.com/index.cfm/2008/4/28/cflock-explained
編集:スコープに関する質問にさらに答えるために<cflock scope="application">
、共有リソースとやり取りするときは常に (たとえば) を使用します。
これは、アプリケーション変数が初期化されているかどうかを確認するためにロックせずに読み取ることができる「ローカル フラグ」を作成するためにページ変数を使用する ColdFusion 8 ドキュメントの例です。
これが解決するのは、排他ロックを条件付きにする必要があるという事実です。これは、ページが読み込まれるたびに排他ロックを実行すると、ロックがより多くの処理時間を消費するため、ボトルネックが発生する可能性があるためです。
これ以降、より良いテクニックが登場したかどうかはわかりませんが、とにかくここに投稿すると思います. ColdFusion のドキュメントには適切なコードが記載されていないことが多いため、これを改善する方法を誰かが確認できるかどうかを知りたいと思っています。
ソース: http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=sharedVars_18.html
<!--- Initialize local flag to false. --->
<cfset app_is_initialized = False>
<!--- Get a readonly lock --->
<cflock scope="application" type="readonly">
<!--- read init flag and store it in local variable --->
<cfset app_is_initialized = IsDefined("APPLICATION.initialized")>
</cflock>
<!--- Check the local flag --->
<cfif not app_is_initialized >
<!--- Not initialized yet, get exclusive lock to write scope --->
<cflock scope="application" type="exclusive">
<!--- Check nonlocal flag since multiple requests could get to the
exclusive lock --->
<cfif not IsDefined("APPLICATION.initialized") >
<!--- Do initializations --->
<cfset APPLICATION.varible1 = someValue >
...
<!--- Set the Application scope initialization flag --->
<cfset APPLICATION.initialized = "yes">
</cfif>
</cflock>
</cfif>