什么时候适合使用 <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 有助于避免文件争用问题。
使用命名锁的另一个原因是如果您不知道当前操作的范围。如果你在一个实例化的 cfc 中,你怎么知道你被实例化到了哪个作用域?变量?会议?应用?良好的封装告诉我们,除了被告知的内容之外,对象什么都不知道。在 CFC 中,使用命名锁并以 CFC 或 CFC 和唯一实例变量命名,具体取决于您的用例。
继续@Mr。Nate 说,只要你担心竞争条件,就使用锁。例如,您可能希望锁定会话初始化,但不锁定后续读取。同样,您可能希望锁定对应用程序范围的写入,而不是读取。
自从 CF6 引入了线程安全的共享变量范围以来,锁定读取的用处要小得多。在糟糕的过去,如果你不小心,你可能会同时读写同一个内存地址。但是,由于 CF 由 Java 驱动,因此这不是问题。
正如他所展示的,命名锁对于锁定任何没有作用域的东西很有用,比如文件读/写。
基于此处的其他建议。
老实说,自从 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)>
使用命名锁定的好时机是当你有一个“事务”你想确保一次完成,例如一次更新数据库中的几个表,或者你只是想确保两个用户是'不一次更新相同的数据库记录,或者在读取或写入服务器上可能有多个用户一次尝试访问它的文件时。
简单地说,任何时候如果两个请求试图同时做同样的事情就会出现问题,然后在它周围放置一个命名锁(或者如果它严格涉及会话、应用程序或服务器范围,那么使用范围锁)。
Ben Nadel 曾在一篇博文中写道:
“在我看来,必须满足两个条件才能要求使用 CFLock:
- 正在访问或更新共享资源。
- 必须存在导致负面结果的竞争条件的可能性。”
您甚至可以嵌套 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>