I don't know that this is necessarily the right way, but over the past 4-5
months I've come up with the following code organization regarding
transactions. I've simplified a bit, of course.
All transactions are defined in my service layer components, IN PUBLIC
METHODS. Since all requests to the persistance layer have to go through the
service layer, that assures that transactions can be applied consistently
and completely in that single strata.
The "public methods" is important, because as you say, it's very likely that
a given service method will need to be called as part of another, larger,
method. For methods that need to be both components in larger method calls,
and stand-alone method calls, I use a dual-method approach:
<cffunction name="addUser" access="public" ...>
<!--- args --->
<cftransaction>
<cfset addUser_(<!--- args --->) />
</cftransaction>
</cffunction>
<cffunction name="addUser_" access="package" ...>
<!--- args --->
<!--- actual business logic --->
</cffunction>
Since all the services are in a single package (are are alone in the
package), only services can call the addUser_() method directly, so there is
no way the application itself can bypass the transaction, because every
public method in the services layer that needs a transaction, uses
CFTRANSACTION.
I don't know what percentage of service methods have both public and package
method, but it's certainly not all of them. There are quite a few that only
have the public method (and consequently have the business logic directly
inside), and actually a fair number that only have the package method.
This type of organization makes far more sense than putting CFTRANSACTION
tags in your persistance layer, IMHO. Transactions are really a
business-logic concern; they have nothing to do with storing anything,
rather they ensure that your stored data is never in a state that violates
business rules.
One could _almost_ make the same argument about foreign keys (foreign key
exceptions aren't runtime errors, they are programming bugs), but I won't,
because they can be such a help (particularly cascading delete/set null).
Cheers,
barneyb
> -----Original Message-----
> From: [EMAIL PROTECTED]
> [mailto:[EMAIL PROTECTED] On Behalf Of Nathan Dintenfass
> Sent: Thursday, June 17, 2004 8:41 AM
> To: [EMAIL PROTECTED]
> Subject: [CFCDev] encapsulating transactions, WAS: Nested
> cftransaction error in CFMX 6.1
>
> This thread brings up a question I've had before -- how do
> you encapsulate
> transactions well?
>
> I have found that there are times I have, for instance, a
> method in a CFC
> that properly belongs in a transaction -- often calling a few "atomic"
> methods that interact with a database that get wrapped into a
> transaction.
> However, I then find there are times I want to call that method inside
> another block of code that should also be in a transaction --
> when that
> happens I end up refactoring everything to get the
> transaction to make sense
> around the largest grouping that is necessary. As a result, I end up
> needing to know a lot about the implementation details to
> know there is a
> transaction being created somewhere down the chain of method calls.
>
> To overcome this I've tried things like having all my atomic
> actions outside
> of transactions, then build a separate CFC that does nothing
> but transaction
> wrappers around those methods. That seems to be the cleanest
> way around the
> problem -- but, even then I find times that I wish I wouldn't
> have to write
> a new method for every permutation of other methods that belong in
> transactions (and, again, it requires that I know a lot about
> implementation
> details rather than just learning the API).
>
> Sean, you say such nested transactions were "bugs" in your
> code -- but, I
> suspect at least some of those were due to people following good
> encapsulation rules (not knowing about the underlying
> implementation that
> used a transaction). Perhaps you (and anyone else with deep
> experience on
> this) could elaborate on how you dealt with those situations?
>
----------------------------------------------------------
You are subscribed to cfcdev. To unsubscribe, send an email
to [EMAIL PROTECTED] with the words 'unsubscribe cfcdev'
in the message of the email.
CFCDev is run by CFCZone (www.cfczone.org) and supported
by Mindtool, Corporation (www.mindtool.com).
An archive of the CFCDev list is available at www.mail-archive.com/[EMAIL PROTECTED]