【发布时间】:2010-09-22 17:48:05
【问题描述】:
什么时候适合使用
具体来说,我有兴趣使用 CFLock 保护应用程序、会话或服务器范围内的共享对象,但我也有兴趣了解 ColdFusion 中锁定的不同用途。
【问题讨论】:
标签: coldfusion locking shared-memory coldfusion-8
什么时候适合使用
具体来说,我有兴趣使用 CFLock 保护应用程序、会话或服务器范围内的共享对象,但我也有兴趣了解 ColdFusion 中锁定的不同用途。
【问题讨论】:
标签: coldfusion locking shared-memory coldfusion-8
使用命名锁定的最佳时机是当您有一个“事务”并且您想确保一次完成所有操作时,例如一次更新数据库中的多个表,或者当您只是想确保两个用户没有同时更新同一个数据库记录,或者在读取或写入服务器上可能有多个用户一次尝试访问它的文件时。
简单地说,任何时候如果两个请求试图同时做同样的事情就会出现问题,然后在它周围放置一个命名锁(或者如果它严格涉及会话、应用程序或服务器范围,然后使用作用域锁)。
Ben Nadel 曾在一篇博文中写道:
“在我看来,必须满足两个条件才能要求 CFLock的使用:
- 正在访问或更新共享资源。
- 必须存在导致 NEGATIVE 结果的竞争条件的可能性。”
您甚至可以嵌套 CFLOCK 标记,例如在事务周围有一个命名锁,以及嵌套在其中的会话或应用程序范围的锁,但要小心这样做——如果你做错了,你可能会遇到“死锁”情况其中没有请求可以执行页面的锁定部分,并且对页面锁定部分的所有请求可能会被阻止,直到超时。 (ColdFusion 手册描述了嵌套锁定的最佳实践。)
【讨论】:
这是 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>
【讨论】:
您应该在读取和写入应用程序范围内可能发生变化的事物时使用。例如:
<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 和唯一的实例变量,具体取决于您的用例。
【讨论】:
以此处的其他建议为基础。
老实说,自从 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. Nate 说,只要你担心竞争条件,就使用锁。例如,您可能希望锁定会话初始化,但不锁定后续读取。同样,您可能希望将写入锁定到应用程序范围,而不是读取。
自从 CF6 引入了线程安全的共享变量范围以来,锁定读取的用处要小得多。在糟糕的过去,如果你不小心,你可能会同时读写同一个内存地址。但是,由于 CF 由 Java 驱动,因此这不是问题。
正如他所展示的,命名锁对于锁定任何没有作用域的东西很有用,比如文件读/写。
【讨论】:
通常情况下,当您在 Application.cfc 之外读取或更改这些变量时,您应该始终将 cflock 用于会话、应用程序和服务器变量,以防止出现竞争条件。这里有一篇文章可能会有所帮助:
http://www.horwith.com/index.cfm/2008/4/28/cflock-explained
编辑:为了进一步回答您关于范围的问题,每当与共享资源交互时,我总是使用<cflock scope="application">(例如)。
【讨论】: