The cflock tag ensures that concurrently executing requests do not run the same section of code simultaneously and thus manipulate shared data structures, files, or CFX tags inconsistently. It is important to remember that cflock protects code sections that access or set data, not the variables themselves.
You protect access to code by surrounding it in a cflock tag; for example:
<cflock scope="Application" timeout="10" type="Exclusive"> <cfif not IsDefined("Application.number")> <cfset Application.number = 1> </cfif> </cflock>
The cflock tag offers two modes of locking, specified by the type attribute:
Exclusive locks (the default lock type): Allow only one request to process the locked code. No other requests can run code inside the tag while a request has an exclusive lock.
Enclose all code that creates or modifies session, application, or server variables in exclusive cflock tags.
Read-only locks: Allow multiple requests to execute concurrently if no exclusive locks with the same scope or name are executing. No requests can run code inside the tag while a request has an exclusive lock.
Enclose code that only reads or tests session, application, or server variables in read-only cflock tags. You specify a read-only lock by setting the type="readOnly" attribute in the cflock tag, for example:
<cflock scope="Application" timeout="10" type="readOnly"> <cfif IsDefined("Application.dailyMessage")> <cfoutput>#Application.dailyMessage#<br></cfoutput> </cfif> </cflock>
Although ColdFusion does not prevent you from setting shared variables inside read-only lock tag, doing so loses the advantages of locking. As a result, you must be careful not to set any session, application, or server variables inside a read-only cflock tag body.
The cflock tag prevents simultaneous access to sections of code, not to variables. If you have two sections of code that access the same variable, they must be synchronized to prevent them from running simultaneously. You do this by identifying the locks with the same scope or name attributes.
Controlling access to data with the scope attribute
When the code that you are locking accesses session, application, or server variables, synchronize access by using the cflock scope attribute.
You can set the attribute to any of the following values:
Scope |
Meaning |
---|---|
Server |
All code sections with this attribute on the server share a single lock. |
Application |
All code sections with this attribute in the same application share a single lock. |
Session |
All code sections with this attribute that run in the same session of an application share a single lock. |
Request |
All code sections with this attribute that run in the same request share a single lock. You use this scope only if your application uses the cfthread tag to create multiple threads in a single request. Locking the Request scope also locks access to Variables scope data. For more information on locking the Request scrope, see Locking thread data and resource access. |
If multiple code sections share a lock, the following rules apply:
Controlling locking access to files and CFX tags with the name attribute
The cflock name attribute provides a second way to identify locks. Use this attribute when you use locks to protect code that manges file access or calls non-thread-safe CFX code.
When you use the name attribute, specify the same name for each section of code that accesses a specific file or a specific CFX tag.
Controlling and minimizing lock time-outs
You must include a timeout attribute in your cflock tag. The timeout attribute specifies the maximum time, in seconds, to wait to obtain the lock if it is not available. By default, if the lock does not become available within the time-out period, ColdFusion generates a Lock type exception error, which you can handle using cftry and cfcatch tags.
If you set the cflock throwOnTimeout attribute to No, processing continues after the time-out at the line after the </cflock> end tag. Code in the cflock tag body does not run if the time-out occurs before ColdFusion can acquire the lock. Therefore, never use the throwOnTimeout attribute for CFML that must run.
Normally, it does not take more than a few seconds to obtain a lock. Very large time-outs can block request threads for long periods of time and radically decrease throughput. Always use the smallest time-out value that does not result in a significant number of time-outs.
To prevent unnecessary time-outs, lock the minimum amount of code possible. Whenever possible, lock only code that sets or reads variables, not business logic or database queries. One useful technique is to do the following:
For example, if you want to assign the results of a query to a session variable, first get the query results using a Variables scope variable in unlocked code. Then, assign the query results to a session variable inside a locked code section. The following code shows this technique:
<cfquery name="Variables.qUser" datasource="#request.dsn#"> SELECT FirstName, LastName FROM Users WHERE UserID = #request.UserID# </cfquery> <cflock scope="Session" timeout="5" type="exclusive"> <cfset Session.qUser = Variables.qUser> </cflock>