I am currently on a performance crusade and have been rewriting lots of my
current projects. One of the biggest changes as a result has been the way I
architect my applications. I have started to use the application scope to cache
commonly used components. For example...
===================================================================================
application.appObjs = structNew();
application.appObjs.securitySQLcfc =
createObject("component","components.security");
application.appObjs.commomSQLcfc =
createObject("component","components.common-sql");
===================================================================================
I recently posted a comment on a blog regarding this when the CF Guru himself
Mr Sean Corfield recommend if I was going to do this, it was possible I could
run into some thread safety issues. Now I have to be honest, I read about this
a year or so back but never really paid attention. However it does have me
worried a little now. From my understanding... because I create my CFCs in the
application scope the CFCâs are treated just like other applications vars ie.
everyone shares it and the issue comes because this could include scopes and
variables in CFCs not VAR-declare. The word singleton was mention, from my JAVA
days I remember this as being an object created once but it can't be
instantiated elsewhere in the application, well if thatâs correct then that
was my desire right?
Ok, on the question, honest....lol
A clients website gets around 5k of traffic a day and I have already cache some
commonly used components however this was before Mr Sean Corfield reminder on
CFCs, Scopes & Thread Safety! I have not had any reported issues with the site.
I am being naive or lucky?
For example, most of the components are just simple SQL statement which I only
want as a singleton, why create the object every time? I also donât think
CFCs, Scopes & Thread Safety would be an issue here, is this correct or not?
example code...
===================================================================================
<cffunction name="getProductMenu" returntype="query" hint="returns product
menu">
<cfquery name="productquery" datasource="#application.appConfig.dbSource#"
username="#application.appConfig.dbUsername#"
password="#application.appConfig.dbPassword#">
SELECT s.storeId, s.name as storeName, s.metaDescription as storeMeta,
s.pos, d.depId, d.name as depName, d.metaDescription as depMeta, d.pos, c.name
as catName, c.metaDescription as catMeta, c.catId, (SELECT COUNT(*) as proCount
FROM products p WHERE p.catId = c.catId AND p.active != 'off') as empt
FROM stores s
LEFT JOIN departments d on s.storeId = d.storeId
LEFT JOIN categories c on d.depId = c.depId
AND (SELECT COUNT(*) as proCount FROM products p WHERE p.catId = c.catId
AND p.active != 'off') > 0
</cfquery>
<cfreturn productquery>
</cffunction>
===================================================================================
The only one code that does concern me is my cart cfc, originally if it was in
a include and I have only just added it to a components, yes its a little messy
at the moment but it works. I have had not issues but if someone could look at
it :)
sorry it long....
===================================================================================
<cffunction name="addtoCart" access="public" hint="adds a new item to the cart">
<!--- if cart session does not exist, create it --->
<cfif not structkeyexists(session,"cartItem")>
<cflock timeout="60" type="exclusive">
<cfset session['cartItem'] = structnew()>
</cflock>
</cfif>
<!---gets option id's from product form--->
<cfif structkeyexists(FORM, "optVal") AND FORM['optVal'] GT 0 AND
FORM['optVal'] NEQ "">
<cfset productOptionId0 = Arraynew(1)>
<cfset val = #form.optVal# - 1>
<cfloop from="0" to="#val#" index=this>
<cfset Vsel = form.sel0>
<cfif isDefined('form.sel0')>
<cfset formval = Evaluate("form.sel" & this)>
<cfset optvals = ListFirst(formval,"*")>
</cfif>
<cfset ArrayAppend( productOptionId0, "#optvals#" ) />
</cfloop>
<cfset optionList = ArrayToList(productOptionId0)>
<cfoutput> #optionList#
<cfparam name="form.productOptionId" default="#optionList#,">
</cfoutput>
</cfif>
<!--- if cart item does not exist, create it --->
<cfif structkeyexists(form,"productid") and form['productid'] neq "" and
structkeyexists(form,"qty") and form['qty'] gt 0>
<!--- create default node for product id --->
<cfset itemNode = "pCode_#form['productid']#_1">
<!--- if no node exists for the given product, create it. --->
<cfif not structkeyexists(session['cartItem'],itemNode)>
<!--- define new node as a struct --->
<cfset session['cartItem'][itemNode] = structnew()>
<cfset session['cartItem'][itemNode]['aQty'] = form['qty']>
<!--- grab the product info based on id --->
<cfquery name="getProd" datasource="#application.appConfig.dbSource#"
username="#application.appConfig.dbUsername#"
password="#application.appConfig.dbPassword#">
SELECT prodID,[name] AS pName,price,saleprice, productCode, tax
FROM products
WHERE prodID = #form['productid']# AND active = 'on'
</cfquery>
<!--- populate the product node with info from the query, check if
there's a sale price --->
<cfif getProd.recordcount>
<cfset session['cartItem'][itemNode]['proCode'] = getProd.productCode>
<cfset session['cartItem'][itemNode]['protax'] = getProd.tax>
<cfset session['cartItem'][itemNode]['aName'] = getProd.pName>
<cfset session['cartItem'][itemNode]['prodId'] = #form['productid']#>
<cfif getProd.saleprice gt 0>
<cfset session['cartItem'][itemNode]['aPrice'] = getProd.saleprice>
<cfelse>
<cfset session['cartItem'][itemNode]['aPrice'] = getProd.price>
</cfif>
</cfif>
<!--- if the product has options being passed, create an options node, in
the product node --->
<cfif structkeyexists(FORM, "optVal") AND FORM['optVal'] GT 0 AND
FORM['optVal'] NEQ "">
<cfset optionsList = form['productOptionId']>
<cfset session['cartItem'][itemNode]['aOpList'] = optionsList>
<!--- loop over option ids populate options with name and price values
--->
<!---|||||||||||||| CAUTION ||||||||||||||||||--->
<!--- "optionname" was a field I added so I didn't have to join your
other tables to get the name --->
<!--- you'll have to create the join to grab the name here before it'll
work --->
<cfloop from="1" to="#listlen(optionsList)#" index="i">
<cfset optionElem = listgetat(optionsList,i)>
<cfset session['cartItem'][itemNode]['bOption'&optionElem] =
structnew()>
<cfquery name="getOptions"
datasource="#application.appConfig.dbSource#"
username="#application.appConfig.dbUsername#"
password="#application.appConfig.dbPassword#">
SELECT options.optionId,
options.name, optionvalues.valueId, optionvalues.value, optionvalues.optionId,
productoptions.valueId, productoptions.productOptionId,
productoptions.optionPrice
FROM options
JOIN optionvalues ON
options.optionId = optionvalues.optionId
JOIN productoptions ON
optionvalues.valueId = productoptions.valueId
WHERE productOptionId =
#optionElem#
</cfquery>
<cfif getOptions.recordcount>
<cfset session['cartItem'][itemNode]['bOption'&optionElem]['name']
= getOptions.value>
<cfset session['cartItem'][itemNode]['bOption'&optionElem]['price']
= getOptions.optionPrice>
</cfif>
</cfloop>
</cfif>
<!--- check for existing cart item with options --->
<cfelseif structkeyexists(session['cartItem'],itemNode) and
structkeyexists(session['cartItem'][itemNode],"aOpList")>
<cfset currentNodes = structkeylist(session['cartItem'])>
<cfset foundNode = false>
<!--- loop over current products in cart to see if there are any absolute
matches --->
<cfloop from="1" to="#listlen(currentNodes)#" index="j">
<cfif listgetat(listgetat(currentNodes,j),2,"_") eq form['productid']
and
compare(session['cartItem'][listgetat(currentNodes,j)]['aOpList'],form['productOptionId'])
eq 0>
<cfset itemNode = listgetat(currentNodes,j)>
<cfset foundNode = true>
<cfbreak>
</cfif>
</cfloop>
<!--- if there's already an existing product with the same options,
increment the qty --->
<cfif foundNode>
<cfset session['cartItem'][itemNode]['aQty'] = form['qty'] +
session['cartItem'][itemNode]['aQty']>
<!--- otherwise create a new item, increment dup item count, create new
product node similar to above --->
<cfelse>
<!--- increments the unique product id if one already exists --->
<cfset currentKeys = structkeylist(session['cartItem'])>
<cfset focusCount = 0>
<cfloop from="1" to="#listlen(currentKeys)#" index="x">
<cfset focusArea = listgetat(listgetat(currentKeys,x),2,"_")>
<cfif focusArea eq form['productid']>
<cfset focusCount = focusCount + 1>
</cfif>
</cfloop>
<cfset focusCount = focusCount + 1>
<cfset itemNode = "pCode_#form['productid']#_#focusCount#">
<cfset session['cartItem'][itemNode] = structnew()>
<cfset session['cartItem'][itemNode]['aQty'] = form['qty']>
<cfquery name="getProd" datasource="#application.appConfig.dbSource#"
username="#application.appConfig.dbUsername#"
password="#application.appConfig.dbPassword#">
SELECT prodID,[name] AS pName,price,saleprice,productCode,tax
FROM products
WHERE prodID = #form['productid']# AND active = 'on'
</cfquery>
<cfif getProd.recordcount>
<cfset session['cartItem'][itemNode]['protax'] = getProd.tax>
<cfset session['cartItem'][itemNode]['proCode'] = getProd.productCode>
<cfset session['cartItem'][itemNode]['aName'] = getProd.pName>
<cfset session['cartItem'][itemNode]['prodId'] = #form['productid']#>
<cfif getProd.saleprice gt 0>
<cfset session['cartItem'][itemNode]['aPrice'] = getProd.saleprice>
<cfelse>
<cfset session['cartItem'][itemNode]['aPrice'] = getProd.price>
</cfif>
</cfif>
<cfif structkeyexists(FORM, "optVal") AND FORM['optVal'] GT 0 AND
FORM['optVal'] NEQ "">
<cfset optionsList = form['productOptionId']>
<cfset session['cartItem'][itemNode]['aOpList'] = optionsList>
<cfloop from="1" to="#listlen(optionsList)#" index="i">
<cfset optionElem = listgetat(optionsList,i)>
<cfset session['cartItem'][itemNode]['bOption'&optionElem] =
structnew()>
<!---|||||||||||||| CAUTION ||||||||||||||||||--->
<!--- "optionname" was a field I added so I didn't have to join
your other tables to get the name --->
<!--- you'll have to create the join to grab the name here before
it'll work --->
<cfquery name="getOptions"
datasource="#application.appConfig.dbSource#"
username="#application.appConfig.dbUsername#"
password="#application.appConfig.dbPassword#">
SELECT
options.optionId, options.name, optionvalues.valueId, optionvalues.value,
optionvalues.optionId, productoptions.valueId, productoptions.productOptionId,
productoptions.optionPrice
FROM options
JOIN optionvalues ON
options.optionId = optionvalues.optionId
JOIN productoptions ON
optionvalues.valueId = productoptions.valueId
WHERE productOptionId =
#optionElem#
</cfquery>
<cfif getOptions.recordcount>
<cfset
session['cartItem'][itemNode]['bOption'&optionElem]['name'] = getOptions.value>
<cfset
session['cartItem'][itemNode]['bOption'&optionElem]['price'] =
getOptions.optionPrice>
</cfif>
</cfloop>
</cfif>
</cfif>
<!--- if a product is already in the cart without options, just increment
the product quantity --->
<cfelseif structkeyexists(session['cartItem'],itemNode) and not
structkeyexists(session['cartItem'][itemNode],"aOpList")>
<cfset currentItemsCount = session['cartItem'][itemNode]['aQty']>
<cfset session['cartItem'][itemNode]['aQty'] = form['qty'] +
currentItemsCount>
</cfif>
</cfif>
</cffunction>
===================================================================================
If you have stuck with me this long thanks for taking time to look over this,
looking forward to your comments :)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
Adobe® ColdFusion® 8 software 8 is the most important and dramatic release to
date
Get the Free Trial
http://ad.doubleclick.net/clk;207172674;29440083;f
Archive:
http://www.houseoffusion.com/groups/cf-talk/message.cfm/messageid:317264
Subscription: http://www.houseoffusion.com/groups/cf-talk/subscribe.cfm
Unsubscribe:
http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=11502.10531.4