Ask Ben: ColdFusion Variable Caching And How To Use It (Simple Demo)

Posted March 28, 2007 at 6:58 PM by Ben Nadel

Tags: ColdFusion, Ask Ben

There is no particular question here. I have been asked about variable caching in ColdFusion and I felt a demo would explain what a back-and-forth email conversation could not. This is a demonstration of very simple variable caching in a small ColdFusion application. Here, we are caching a value (a Struct in this case) in the APPLICATION scope. We are then referencing it on the index.cfm page.

The demo has two pages. The first is our Application.cfm page. I used the Application.cfm rather than the Application.cfc as I feel for demonstration purposes, there is less "noise" in the Application.cfm page. Then, we have our index.cfm page. The index page merely references the cached variable and displays the data.

Application.cfm

  • <!--- Kill extra output. --->
  • <cfsilent>
  •  
  • <!---
  • Define the application. Here, I am setting a very small
  • Application timeout (since I am on the work server) -
  • In reality, this would either be left out (using CFAdmin
  • default) or 2 days or something.
  • --->
  • <cfapplication
  • name="SimpleCacheDemo"
  • applicationtimeout="#CreateTimeSpan( 0, 0, 5, 0 )#"
  • sessionmanagement="false"
  • setclientcookies="true"
  • />
  •  
  •  
  • <!--- Set request settings. --->
  • <cfsetting
  • showdebugoutput="false"
  • />
  •  
  •  
  • <!---
  • We need to check to see if our application is
  • initialized. For convenience, I am going to store an
  • Applcation variable that flags for initialization
  • (DateInitialized). If this value does NOT yet exists
  • OR the user has flagged a reset via the URl, we are
  • going to initialize the application.
  •  
  • NOTE: By initializing the application using the
  • Application.cfm (or Application.cfc) we ensure that the
  • application get initialized no matter what page in
  • our application gets requested.
  • --->
  • <cfif (
  • (NOT StructKeyExists( APPLICATION, "DateInitialized" )) OR
  • StructKeyExists( URL, "resetapp" )
  • )>
  •  
  • <!---
  • Either a re-init of the application was requested,
  • or the app has not yet been requested. Since we
  • are potentially updating live, shared memory
  • (APPLICATION), throw a Lock on it to force a
  • single thread.
  • --->
  • <cflock
  • scope="APPLICATION"
  • type="EXCLUSIVE"
  • timeout="20">
  •  
  • <!---
  • Since we are in a multi-threaded environment,
  • it is possible that why we were locking, someone
  • else swooped in an performed the initialization
  • before we could do it. Therefore, we need to
  • perform a double-check lock (pattern) to see if
  • initialization is still required.

  • However, if we have requested a manual re-init,
  • then we are going to proceed no matter what.
  • --->
  • <cfif (
  • (NOT StructKeyExists( APPLICATION, "DateInitialized" )) OR
  • StructKeyExists( URL, "resetapp" )
  • )>
  •  
  • <!---
  • We see that, indeed, the application still
  • is not initialized (DateInitialization flag
  • has not been set). We can now safely proceed
  • with application initialization.
  • --->
  •  
  • <!---
  • Clear the existing Application to make sure
  • we don't have any old data.
  • --->
  • <cfset StructClear( APPLICATION ) />
  •  
  • <!--- Flag initialization. --->
  • <cfset APPLICATION.DateInitialized = Now() />
  •  
  •  
  • <!---
  • Now, we are going to cache some objects. For
  • now, we are simply caching built in CF data
  • types for demonstration. However, these
  • could easily be ColdFusion components (or
  • even Java objects) created using the
  • CreateObject() function.
  • --->
  •  
  • <!---
  • Cache this struct. By declaring the struct
  • directly in the APPLICATION scope, we are
  • caching in the APPLICATION scope. This
  • struct will exist for as long as the
  • Application does (or until the scope is
  • cleared or the variable is deleted).
  • --->
  • <cfset APPLICATION.Actress = StructNew() />
  •  
  • <!--- Set values in the struct. --->
  • <cfset APPLICATION.Actress[ "Christina" ] = "Cox" />
  • <cfset APPLICATION.Actress[ "Lori" ] = "Petty" />
  • <cfset APPLICATION.Actress[ "Linda" ] = "Hamilton" />
  • <cfset APPLICATION.Actress[ "Angella" ] = "Bassette" />
  •  
  • <!---
  • You could perform as much cacheing as you
  • want at this point. I am only caching one
  • object for demonstration purposes.
  • --->
  •  
  • </cfif>
  •  
  • </cflock>
  •  
  • </cfif>
  •  
  • </cfsilent>

Index.cfm

  • <html>
  • <head>
  • <title>Simple ColdFusion Cache Demo</title>
  • </head>
  • <body>
  •  
  • <h1>
  • Here Are Your Cached Actresses (Lucky You!)
  • </h1>
  •  
  • <cfoutput>
  •  
  • <!---
  • Loop over the actresses in the struct. We can
  • reference the cached struct directly in the
  • APPLICATION. Technically we are referencing shared
  • memory, and there are those that would argue this
  • requires a CFLock to be used... however, I am of
  • the mind set that even the "worst case" scenario
  • in this case will not be bad - therefore, no lock.
  • --->
  • <cfloop
  • item="FirstName"
  • collection="#APPLICATION.Actress#">
  •  
  • <p>
  • #FirstName#
  • #APPLICATION.Actress[ FirstName ]#
  • </p>
  •  
  • </cfloop>
  •  
  • </cfoutput>
  •  
  • </body>
  • </html>

I am sure this is pure review for many of you, but it may be new to even more of you. Please let me know if any further explanation is needed.



Reader Comments

Mar 28, 2007 at 10:00 PM // reply »
37 Comments

Nicely done, Ben. One clarification: the cflock and double-check for if NOT StructKeyExists( APPLICATION, "DateInitialized" ) is *only* necessary because the StructKeyExists( URL, "resetapp" ) is included, correct? If we didn't want to allow re-initialization of the Application-scoped variables via the URL (for security reasons), then the cflock and double-check are unnecessary in CF 6.1+.


Mar 29, 2007 at 7:20 AM // reply »
11,246 Comments

@Aaron,

I actually made one small mistake. In the inner CFIF statement, I forgot to check for the manual reset. I have updated the code (see the CFIF inside the CFLock). If someone requests a manual reset, the DateInitialized IS going to be present which is why the original code wouldn't work.

And to answer your question, Yes, the double-check locking is required ONLY because of the manual reset. If this code was fired because the application was just starting up, theoretically, this would be a single-threaded environment. But actually, as I am even typing this, I am not so sure. Because these are based on page requests (the Application.cfm does not get processed until a page is requested) then I actually don't see why two simultaneous requests couldn't cause conflicts - see, checking for DateInitialized existence and then setting the value has some time between it (nanoseconds??). Is it possible for two threads to overlap in this action???? I was have to say Yes to be cautious.

So, long story short, when using Application.cfm, I would recommend always doing the double-check locking. But, if you are using the Application.CFC with OnApplicationStart(), ColdFusion takes care of single-threading that on application start. Of course, if you put a manual reset in that, I would again, perform a double-check lock.


Mar 29, 2007 at 12:06 PM // reply »
2 Comments

Ben,

Why not perform the CFLOCK first and then do the check to make sure the app is not already initialized. If it is then bail on the lock otherwise complete the initialization action?

Ron


Mar 29, 2007 at 12:23 PM // reply »
11,246 Comments

@Ron,

If you do the CFLock out side of the CFIF statements that you force a portion of the Application.cfm to become single-threaded regardless of whether or not any app-initialization is going to take place. CFLock comes with slight overhead; for small sites, this might not matter, however, for a heavily trafficked site, this slight overhead on every single page request might start to slow things down.

Would people notice the slow down? Not sure, can't say. But, as a generally good practice, I would say you want to avoid locking whenever possible.


Jun 15, 2008 at 11:07 AM // reply »
2 Comments

Hi, slightly off topic but i noticed you use StructKeyExists alot instead of isdefined(), is there really much difference. Ie ,y friend told me not to use isdefined() anymore as it checks all the scopes and used more resources but is there really much difference?

Thanks pspboy


Jun 15, 2008 at 11:11 AM // reply »
11,246 Comments

@PspBoy,

IsDefined() works. But, personally, I think it is a "weak" statement. I like my ColdFusion code to be as assertive and descriptive as possible. If I know that a key should or should not exist in a given Struct, then I use StructKeyExists() because it is a very bold statement. There's something about IsDefined() that seems almost like a cop-out; it's like you're not even sure if it will be in a given struct or not.

It's a personal choice, mostly. But, I have heard that StructKeyExists() is faster.


Dec 1, 2009 at 4:19 PM // reply »
11 Comments

Thanks for writing this.

I needed a way to Clear all persistent Application variables this worked great.

<cfset StructClear( APPLICATION ) />

However can I have this in a non application.cfm file for it to work?

Dave


Jan 9, 2010 at 10:33 PM // reply »
11,246 Comments

@Dave,

You should be able to put that anywhere in your application (since APPLICATION is a globally accessible scope). However, you're probably gonna want to do it right before you initialize the Application scope, otherwise you might get "undefined" variable errors in the rest of the page request.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools