Thursday, February 12, 2009

CF: How to detect nested transactions within cftransaction

Sometimes it cannot be helped. You are expanding ColdFusion code and have to implement transactions. You have to, then, use components that cannot be changed, that, in turn, may have to do transactions. Now the problem, ColdFusion does not like nested transactions. Nested transactions are simply not supported.

Well, at least if I could detect whether I am in a transaction I could write around this I think. But there is no way that I have found. No clear posting on how to do this.

First approach I used was to create a function that would open and close a transaction, then detect the error thrown. If the error was thrown I was assuming that we were in a transaction and thus could not open a new one, a fuction like this:


<CFSET var blnReturn = false>
<CFTRY>
<CFTRANSACTION>
<!--- emptry transaction tag --->

</CFTRANSACTION>
<CFCATCH type="Any">
<CFSET blnReturn=true>
</CFCATCH>

</CFTRY>
<CFRETURN blnReturn>


Unfortunatly, this does not work. When CF throws an error for nesting, even within the try/catch block for the purposfully nested transaction, the transaction wrapper is removed. Thus you are hosed if an error occurs later down the execution.

What to do then?

After much researching and failure, here is the approach I did find working. The trouble with this is, that there is no guarantee that it will work in future versions of CF, which I hope will introduce a simple function like InTransaction() . We are using the ColdFusion Java implementation of the Transaction Tag to find out whether we have a current transaction. This is the fully wrapped function.

<CFFUNCTION name="InTransaction" access="public" displayname="checks to see whether we are currently running a database transaction. returns true or false." output="No" RETURNTYPE="boolean">
<CFSET var objTrans ="">
<CFSET var blnActiveTransaction=false>
<CFSET var objCurrentTrans="">
<!--- Call to CF implementation of TransactionTag to expose Java functions --->
<cfobject type="Java" class="coldfusion.tagext.sql.TransactionTag" name="objTrans" action="create">
<!--- objCurrentTrans will become undefined if the Java function call getCurrent() returns Null,
otherwise this returns a pointer to current transaction instance --->

<cfset objCurrentTrans = objTrans.getCurrent()>
<cfif IsDefined("objCurrentTrans")>
<CFSET blnActiveTransaction=true>
</cfif>
<!--- return result --->
<CFRETURN blnActiveTransaction>
</CFFUNCTION>


This works in ColdFusion 8 and 7.

Cheers.

3 comments:

Unknown said...

in railo you can do this as follows
getPageContxt().getDataSourceManager().isAutoCommit()

Unknown said...

In CF9 you can use nested attribute in cftransaction tag.

Adam Cameron said...

Just a heads-up: I've simplified this and put it up on CFLIB: http://cflib.org/udf/isInTransaction. Am happy to change the attribution to your name if you can give me your details.

Thanks for blogging about this.

--
Adam