Integrates with Spring's high level persistence integration APIs
such as AdoTemplate.

This chapter is divided up into a number of sections, each detailing
one of the value-adds or technologies of the Spring Framework's
transaction support. The chapter closes with some discussion of best
practices surrounding transaction management.

The first section, entitled Motivations describes why one would want
to use the Spring Framework's transaction abstraction as opposed to
using System.Transactions or a specific data access technology
transaction API.

The second section, entitled Key Abstractions outline the core
classes as well as how to configure them.

17.2. Motivations

The data access technology landscape is a broad one, within the .NET
BCL there are three APIs for performing transaction management, namely
ADO.NET, Enterprise Services, and System.Transactions. Other data access
technologies such as object relational mappers and result-set mapping
libraries are also gaining in popularity and each come with their own APIs
for transaction management. As such, code is often directly tied to a
particular transaction API which means you must make an up-front decision
which API to use in your application. Furthermore, if the need arises to
change your approach, it quite often will not be a simple refactoring.
Using Spring's transaction API you can keep the same API across different
data access technologies. Changing the underlying transaction
implementation that is used is a simple matter of configuration or a
centralized programmatic change as compared to a major overhauling.

Hand in hand with the variety of options available is the
establishment generally agreed upon best practices for data access. Martin
Fowler's book, Patterns of Enterprise Application Architecture, is an
excellent source of approaches to data access that have been successful in
the real world. One approach that is quite common is to introduce a data
access layer into your architecture. The data access layer is concerned
not only with providing some portability between different data access
technologies and databases but its scope is strictly related to data
access. A simple data access layer would be not much more than data access
objects (DAOs) with 'Create/Retrieve/Update/Delete' (CRUD) methods devoid
of any business logic. Business logic resides in another application
layer, the business service layer, in which business logic will call one
or more DAOs to fulfill a higher level end-user function.

In order to perform this end-user function with all-or-nothing
transactional semantics, the transaction context is controlled by the
business service layer (or other 'higher' layers). In such a common
scenario, an important implementation detail is how to make the DAO
objects aware of the 'outer' transaction started in another layer. A
simplistic implementation of a DAO would perform its own connection and
transaction management, but this would not allow grouping of DAO
operations with the same transaction as the DAO is doing its own
transaction/resource management. As such there needs to be a means to
transfer the connection/transaction pair managed in the business service
layer to the DAOs. There are a variety of ways to do this, the most
invasive being the explicitly pass a connection/transaction object as
method arguments to your DAOs. Another way is to store the
connection/transaction pair in thread local storage. In either case, if
you are using ADO.NET you must invent some infrastructure code to perform
this task.

But wait, doesn't Enterprise Services solve this problem - and what
about the functionality in the System.Transactions namespace? The answer
is yes...and no. Enterprise Services lets you use the 'raw' ADO.NET API
within a transaction context such that multiple DAO operations are grouped
within the same transaction. The downside to Enterprise Services is that
it always uses distributed (global) transactions via the Microsoft
Distributed Transaction Coordinator (MS-DTC). For most applications this
is overkill just to get this functionality as global transactions are
significantly less performant than local ADO.NET transactions.

There are similar issues with using the 'using TransactionScope'
construct within the new System.Transactions namespace. The goal with
TransactionScope is to define a, well - transaction scope - within a using
statement. Plain ADO.NET code within that using block will then be a local
ADO.NET based transaction if only a single transactional resource is
accessed. However, the 'magic' of System.Transactions (and the database)
is that local transactions will be promoted to distributed transactions
when a second transaction resource is detected. The name that this goes by
is Promotable Single Phase Enlistment (PSPE). However, there is a big
caveat - opening up a second IDbConnection object to the same database
with the same database string will trigger promotion from local to global
transactions. As such, if your DAOs are performing their own connection
management you will end up being bumped up to a distributed transaction.
In order to avoid this situation for the common case of an application
using a single database, you must pass around a connection object to your
DAOs. It is also worth to note that many database providers (Oracle for
sure) do not yet support PSPE and as such will always use a distributed
transaction even if there is only a single database.

Last but not least is the ability to use declarative transaction
management. Not many topics in database transaction-land give developers
as much 'bang-for-the-buck' as declarative transactions since the noisy
tedious bits of transactional API code in your application are pushed to
the edges, usually in the form of class/method attributes. Only Enterprise
Services offers this feature in the BCL. Spring fills the gap - it
provides declarative transaction management if you are using local ADO.NET
or System.Transactions (the most popular) or other data access
technologies. Enterprise Services is not without it small warts as well,
such as the need to separate your query/retrieve operations from your
create/update/delete operations if you want to use different isolation
levels since declarative transaction metadata can only be applied at the
class level. Nevertheless, all in all, Enterprise Services, in particular
with the new 'Services Without Components' implementation for XP
SP2/Server 2003, and hosted within the same process as your application
code is as good as it gets out of the .NET box. Despite these positive
points, it hasn't gained a significant mindshare in the development
community.

Spring's transaction support aims to relieve these 'pain-points'
using the data access technologies within the BCL - and for other third
party data access technologies as well. It provides declarative
transaction management with a configurable means to obtain transaction
option metadata - out of the box attributes and XML within Spring's IoC
configuration file are supported.

Finally, Spring's transaction support lets you mix data access
technologies within a single transaction - for example ADO.NET and
NHibernate operations.

With this long winded touchy/feely motivational section behind us,
lets move on to see the code.

17.3. Key Abstractions

The key to the Spring transaction management abstraction is the
notion of a transaction strategy. A transaction
strategy is defined by the
Spring.Transaction.IPlatformTransactionManager
interface, shown below:

This is primarily a 'SPI' (Service Provider Interface), although it
can be used Programatically. Note that in keeping with the Spring
Framework's philosophy, IPlatformTransactionManager
is an interface, and can thus be easily mocked or stubbed as necessary.
IPlatformTransactionManager implementations
are defined like any other object in the IoC container. The following
implementations are provided

HibernatePlatformTransactionManager -
local transaction manager for use with NHibernate or mixed
ADO.NET/NHibernate data access operations.

Under the covers, the following API calls are made. For the
AdoPlatformTransactionManager, Transaction.Begin(), Commit(), Rollback().
ServiceDomainPlatformTransactionManager uses the 'Services without
Components' update so that your objects do not need to inherit from
ServicedComponent or directly call the Enterprise Services API
ServiceDomain.Enter(), Leave; ContextUtil.SetAbort().
TxScopePlatformTransactionManager calls; new TransactionScope();
.Complete(), Dispose(), Transaction.Current.Rollback(). Configuration
properties for each transaction manager are specific to the data access
technology used. Refer to the API docs for comprehensive information but
the examples should give you a good basis for getting started. The
HibernatePlatformTransactionManager is described more in the following
section .

The GetTransaction(..) method returns a
ITransactionStatus object, depending on a
ITransactionDefinition parameters. The returned
ITransactionStatus might represent a new or
existing transaction (if there was a matching transaction in the current
call stack - with the implication being that a
ITransactionStatus is associated with a logical
thread of execution.

The ITransactionDefinition interface
specified

Isolation: the degree of isolation this transaction has from the
work of other transactions. For example, can this transaction see
uncommitted writes from other transactions?

Propagation: normally all code executed within a transaction
scope will run in that transaction. However, there are several options
specifying behavior if a transactional method is executed when a
transaction context already exists: for example, simply continue
running in the existing transaction (the common case); or suspending
the existing transaction and creating a new transaction.

Timeout: how long this transaction may run before timing out
(and automatically being rolled back by the underlying transaction
infrastructure).

Read-only status: a read-only transaction does not modify any
data. Read-only transactions can be a useful optimization in some
cases (such as when using NHibernate).

These settings reflect standard transactional concepts. If
necessary, please refer to a resource discussing transaction isolation
levels and other core transaction concepts because understanding such core
concepts is essential to using the Spring Framework or indeed any other
transaction management solution.

The ITransactionStatus interface
provides a simple way for transactional code to control transaction
execution and query transaction status.

Regardless of whether you opt for declarative or programmatic
transaction management in Spring, defining the correct
IPlatformTransactionManager implementation
is absolutely essential. In good Spring fashion, this important definition
typically is made using via Dependency Injection.

IPlatformTransactionManager
implementations normally require knowledge of the environment in which
they work, ADO.NET, NHibernate, etc. The following example shows how a
standard ADO.NET based
IPlatformTransactionManager can be
defined.

We must define a Spring IDbProvider
and then use Spring's
AdoPlatformTransactionManager, giving it a
reference to the IDbProvider. For more information
on the IDbProvider abstraction refer to the next
chapter.

Note that in all these cases, application code will not need to
change at all since, dependency injection is a perfect companion to using
the strategy pattern. We can now change how transactions are managed
merely by changing configuration, even if that change means moving from
local to global transactions or vice versa.

17.4. Resource synchronization with transactions

How does application code participate with the resources (i.e.
Connection/Transactions/Sessions) that are created/reused/cleanedup via
the different transaction managers? There are two approaches - a
high-level and a low-level approach

17.4.1. High-level approach

The preferred approach is to use Spring's high level persistence
integration APIs. These do not replace native APIs, but internally
handle resource creation/reuse, cleanup, and optional transaction
synchronization (i.e. event notification) of the resources and exception
mapping so that user data access code doesn't have to worry about these
concerns at all, but can concentrate purely on non-boilerplate
persistence logic. Generally, the same inversion of control approach is
used for all persistence APIs. In this approach the API has a callback
method or delegate that presents the user code with the relevant
resource ready to use - i.e. a DbCommand with its Connection and
Transaction properties set based on the transaction option metadata.
These classes go by the naming scheme 'template', examples of which are
AdoTemplate and HibernateTemplate. Convenient 'one-liner' helper methods
in these template classes build upon the core callback/IoC design by
providing specific implementations of the callback interface.

17.4.2. Low-level approach

A utility class can be used to directly obtain a
connection/transaction pair that is aware of the transactional calling
context and returns a pair suitable for that context. The class
ConnectionUtils contains the static method
ConnectionTxPair GetConnectionTxPair(IDbProvider provider)
which serves this purpose.

17.5. Declarative transaction management

Most Spring users choose declarative transaction management. It is
the option with the least impact on application code, and hence is most
consistent with the ideals of a non-invasive
lightweight container.

Spring's declarative transaction management is made possible with
Spring AOP, although, as the transactional aspects code comes with Spring
and may be used in a boilerplate fashion, AOP concepts do not generally
have to be understood to make effective use of this code.

The basic approach is to specify transaction behavior (or lack of
it) down to the individual method level. It is also possible to mark a
transaction for rollback by setting the 'RollbackOnly' property on the
ITransactionStatus object returned from the IPlatformTransactionManager
within a transaction context if necessary. Some of the highlights of
Spring's declarative transaction management are:

Declarative Transaction management works in any environment. It
can work with ADO.NET, System.Transactions, NHibernate etc, with
configuration changes only.

Enables declarative transaction management to be applied to any
class, not merely special classes such as those that inherit from
ServicedComponent or other infrastructure related base classes.

Declarative rollback rules. Rollback rules can be control
declaratively and allow for only specified exceptions thrown within a
transactional context to trigger a rollback

Spring gives you an opportunity to customize transactional
behavior, using AOP. For example if you want to insert custom behavior
in the case of a transaction rollback, you can. You can also add
arbitrary advice, along with the transactional advice.

Spring does not support propagation of transaction context
across remote calls.

Note rollback rules as configured from XML are still under
development.

The concept of rollback rules is important: they enable us to
specify which exceptions should cause automatic roll back. We specify this
declaratively, in configuration, not in code. So, while we can still set
RollbackOnly on the
ITransactionStatus object to roll the
current transaction back Programatically, most often we can specify a rule
that MyApplicationException must always result in rollback. This has the
significant advantage that business objects don't need to depend on the
transaction infrastructure. For example, they typically don't need to
import any Spring APIs, transaction or other. If you would like to
rollback the transaction programmatically and you are using declarative
transaction management, use the utility method

TransactionInterceptor.CurrentTransactionStatus.RollbackOnly = true;

17.5.1. Understanding
Spring's declarative transaction implementation

The aim of this section is to dispel the mystique that is
sometimes associated with the use of declarative transactions. It is all
very well for this reference documentation to simply tell you to
annotate your classes with the Transaction attribute and add some
boilerplate XML to your IoC configuration, and then expect you to
understand how it all works. This section will explain the inner
workings of Spring's declarative transaction infrastructure to help you
navigate your way back upstream to calmer waters in the event of
transaction-related issues.

Note

Looking at the Spring source code is a good way to get a real
understanding of Spring's transaction support. You should find the API
documentation informative and complete. We suggest turning the logging
level to 'DEBUG' in your Spring-enabled application(s) during
development to better see what goes on under the hood.

The most important concepts to grasp with regard to Spring's
declarative transaction support are that this support is enabled via AOP
proxies, and that the transactional advice is driven by metadata
(currently XML- or attribute-based). The combination of a proxy with
transactional metadata yields an AOP proxy that uses a
TransactionInterceptor in conjunction with an
appropriate IPlatformTransactionManager
implementation to drive transactions around method invocations.

Note

Although knowledge of AOP (and specifically Spring AOP) is not
required in order to use Spring's declarative transaction support, it
can help. Spring AOP is thoroughly covered in the AOP chapter.

Conceptually, calling a method on a transactional proxy looks like
this.

The flow of events is the following. First the set of objects you
would like to apply AOP transactional advice to are identified. There
are a variety of ways to configure the Spring IoC container to create
proxies for the defined object definitions. The standard Spring AOP
based options are

There is also a convenience subclass of
ProxyFactoryObject, namely
TransactionProxyFactoryObject, that sets some
common default values for the specific case of applying transactional
advice.

The DefaultAdvisorAutoProxyCreator is very
powerful and is the means by which Spring can be configured to use
attributes to identify the pointcuts where transaction advice should be
applied. The advisor that performs that task is
TransactionAttributeSourceAdvisor.

Note

Note, think of the word 'Attribute' in this class name not as
the .NET attribute but as the transaction 'options' you want to
specify. This name is inherited from the Java version and the name
will be changed in the RC1 release to avoid confusion since a common
naming convention when creating classes are .NET attributes is to
put the word 'Attribute' in the name.

Which one of the many options available should you choose for your
development? That depends, each one has it own set of pro's and con's
which will be discussed in turn in the following sections.

With the transactional AOP proxy now created we can discuss the
flow of events in the code as proxied methods are invoked. When the
method is invoked, before calling the target object's method, a
transaction is created if one hasn't already been created. Then the
target method is invoked. If there was an exception throw, the
transaction is typically rolled back, but it can also be committed if
the exception type specified in the transaction option, NoRollbackFor,
matches the thrown exception. If no exception was thrown, that is taken
as a sign of success and the transaction is committed.

When using other AOP advice with the transactional advice you can
set the order of the 'interceptor chain' so that, for example,
performance monitoring advice always precede the transactional
advice.

17.5.2. A First Example

Consider the following interface. The intent is to convey the
concepts to you so you can concentrate on the transaction usage and not
have to worry about domain specific details. The
ITestObjectManager is a poor-mans
business service layer - the implementation of which will make two DAO
calls. Clearly this example is overly simplistic from the service layer
perspective as there isn't any business logic at all!. The 'service'
interface is shown below.

Note the Transaction attribute on the methods. Other options such
as isolation level can also be specified but in this example the default
settings are used. However, please note that the mere presence of the
Transaction attribute is not enough to actually turn on the
transactional behavior - the Transaction attribute is simply metadata
that can be consumed by something that is Transaction attribute-aware
and that can use the said metadata to configure the appropriate objects
with transactional behavior.

The TestObjectDao property has basic create
update delete and find method for the 'domain' object TestObject.
TestObject in turn has simple properties like name and age.

The Create and Delete method implementation is shown below. Note
that this uses the AdoTemplate class discussed in
the following chapter. Refer to Section 17.4, “Resource synchronization with transactions” for
information on the interaction between Spring's high level persistence
integration APIs and transaction management features.

The TestObjectManager is configured with
the DAO objects by standard dependency injection techniques. The client
code, which in this case directly asks the Spring IoC container for an
instance of ITestObjectManager, will
receive a transaction proxy with transaction options based on the
attribute metadata. Note that typically the
ITestObjectManager would be set on yet
another higher level object via dependency injection, for example a web
service.

This is standard Spring configuration and as such provides you
with the flexibility to parameterize your connection string and to
easily switch implementations of your DAO objects. The configuration to
create a transactional proxy for the manager class is shown
below.

Granted this is a bit verbose and hard to grok at first sight -
however you only need to grok this once as it is 'boiler plate' XML you
can reuse across multiple projects. What these object definitions are
doing is to instruct Spring's to look for all objects within the IoC
configuration that have the [Transaction] attribute and then apply the
AOP transaction interceptor to them based on the transaction options
contained in the attribute. The attribute serves both as a pointcut and
as the declaration of transactional option information.

Since this XML fragment is not tied to any specific object
references it can be included in its own file and then imported via the
<import> element. In examples and test code this XML configuration
fragment is named autoDeclarativeServices.xml See ??? for more information.

The classes and their roles in this configuration fragment are
listed below

TransactionAttributeSourceAdvisor is an
AOP Advisor that holds the TransactionInterceptor, which is the
advice, and a pointcut (where to apply the advice), in the form of a
TransactionAttributeSource.

AttributesTransactionAttributeSource is
an implementation of the
ITransactionAttributeSource interface that
defines where to get the transaction metadata defining the
transaction semantics (isolation level, propagation behavior, etc)
that should be applied to specific methods of specific classes. The
transaction metadata is specified via implementations of the
ITransactionAttributeSource interface. This
example shows the use of the implementation
Spring.Transaction.Interceptor.AttributesTransactionAttributeSource
to obtain that information from standard .NET attributes. By the
very nature of using standard .NET attributes, the attribute serves
double duty in identifying the methods where the transaction
semantics apply. Alternative implementations of
ITransactionAttributeSource available are
MatchAlwaysTransactionAttributeSource,
NameMatchTransactionAttributeSource, or
MethodMapTransactionAttributeSource.

MatchAlwaysTransactionAttributeSource
is configured with a ITransactionAttribute instance that is
applied to all methods. The shorthand string representation,
i.e. PROPAGATION_REQUIRED can be used

AttributesTransactionAttributeSource
: Use a standard. .NET attributes to specify the transactional
information. See TransactionAttribute class
for more information.

NameMatchTransactionAttributeSource
allows ITransactionAttributes to be matched by method name. The
NameMap IDictionary property is used to specify the mapping. For
example

Key values can be prefixed and/or suffixed with wildcards
as well as include the full namespace of the containing
class.

MethodMapTransactionAttributeSource
: Similar to NameMatchTransactionAttributeSource but specifies
that only fully qualified method names (i.e. type.method,
assembly) and wildcards can be used at the start or end of the
method name for matching multiple methods.

DefaultAdvisorAutoProxyCreator: looks
for Advisors in the context, and automatically creates proxy objects
which are the transactional wrappers

Refer to the following section for a more convenient way to
achieve the same goal of declarative transaction management using
attributes.

17.5.3. Declarative transactions using the transaction namespace

Spring provides a custom XML schema to simplify the configuration
of declarative transaction management. If you would like to perform
attribute driven transaction management you first need to register the
custom namespace parser for the transaction namespace. This can be done
in the application configuration file as shown below

Instead of using the XML configuration listed at the end of the
previous section (declarativeServices.xml you can use the following.
Note that the schemaLocation in the objects element is needed only if
you have not installed Spring's schema into the proper VS.NET 2005
location. See the chapter on VS.NET integration for more details.

You can actually omit the
'transaction-manager' attribute in the
<tx:attribute-driven/> tag if the object
name of the
IPlatformTransactionManager that you
want to wire in has the name
'transactionManager'. If the
PlatformTransactionManager object
that you want to dependency inject has any other name, then you have
to be explicit and use the 'transaction-manager'
attribute as in the example above.

The various optional elements of the
<tx:attribute-driven/> tag are summarised in the following
table

Table 17.1. <tx:annotation-driven/>
settings

Attribute

Required?

Default

Description

transaction-manager

No

transactionManager

The name of transaction manager to use. Only
required if the name of the transaction manager is not
transactionManager, as in the example
above.

proxy-target-type

No

Controls what type of transactional proxies are
created for classes annotated with the
[Transaction] attribute. If
"proxy-target-type" attribute is set to
"true", then class-based proxies will be
created (proxy inherits from target class, however calls are
still delegated to target object via composition. This allows
for casting to base class. If
"proxy-target-type" is
"false" or if the attribute is omitted,
then a pure composition based proxy is created and you can
only cast the proxy to implemented interfaces. (See the
section entitled Section 13.6, “Proxying mechanisms” for a
detailed examination of the different proxy
types.)

order

No

Defines the order of the transaction advice that
will be applied to objects annotated with
[Transaction]. More on the rules related to
ordering of AOP advice can be found in the AOP chapter (see
section Section 13.3.2.5, “Advice Ordering”). Note
that not specifying any ordering will leave the decision as to
what order advice is run in to the AOP
subsystem.

Note

The "proxy-target-type" attribute on the
<tx:attribute-driven/> element controls what
type of transactional proxies are created for classes annotated with
the Transaction attribute. If
"proxy-target-type" attribute is set to
"true", then inheritance-based proxies will be
created. If "proxy-target-type" is
"false" or if the attribute is omitted, then
composition based proxies will be created. (See the section entitled
Section 13.6, “Proxying mechanisms” for a detailed examination of
the different proxy types.)

You can also define the transactional semantics you want to apply
through the use of a <tx:advice> definition. This lets you define
the transaction metadata such as propagation and isolation level as well
as the methods for which that metadata applies external to the code
unlike the case of using the transaction attribute. The
<tx:advice> definition creates an instance of a
ITransactionAttributeSource during parsing time. Switching to use
<tx:advice> instead of <tx:attribute-driven/> in the example
would look like the following

The <tx:advice/> definition reads as “... all methods on
starting with 'Get' are to execute in the context of a read-only
transaction, and all other methods are to execute with the default
transaction semantics”. The 'transaction-manager' attribute of the
<tx:advice/> tag is set to the name of the
PlatformTransactionManager object that is going to actually drive the
transactions (in this case the 'transactionManager' object).

You can also use the AOP namespace <aop:advisor> element to
tie together a pointcut and the above defined advice as shown
below.

This is assuming that the service layer class, TestObjectManager,
in the namespace Spring.TxQuickStart.Services. The <aop:config/>
definition ensures that the transactional advice defined by the
'txAdvice' object actually executes at the appropriate points in the
program. First we define a pointcut that matches any operation defined
on classes in the Spring.TxQuickStart.Services (you can be more
selective in your regular expression). Then we associate the pointcut
with the 'txAdvice' using an advisor. In the example, the result
indicates that at the execution of a 'SaveTwoTestObjects' and
'DeleteTwoTestObject', the advice defined by 'txAdvice' will be
run.

The various transactional settings that can be specified using the
<tx:advice/> tag. The default <tx:advice/> settings are
listed below and are the same as when you use the Transaction
attribute.

The propagation setting is
TransactionPropagation.Required

The isolation level is
IsolationLevel.ReadCommitted

The transaction is read/write

The transaction timeout defaults to the default timeout of the
underlying transaction system, or none if timeouts are not
supported

EnterpriseServicesInteropOption (.NET 2.0 only with
TxScopeTransactionManager) - options between transaction created
with System.Transactions and transactions created through
COM+

Any exception will trigger rollback.

These default settings can be changed; the various attributes of
the <tx:method/> tags that are nested within
<tx:advice/> and
<tx:attributes/> tags are summarized
below:

Table 17.2. <tx:method/> settings

Attribute

Required?

Default

Description

name

Yes

The method name(s) with which the transaction
attributes are to be associated. The wildcard (*) character
can be used to associate the same transaction attribute
settings with a number of methods; for example,
'Get*',
'Handle*', 'On*Event',
and so forth.

Note that setting the TransactionPropagation to Nested will throw
a NestedTransactionNotSupportedException in a case where an actual
nested transaction occurs, i.e. not in the case of applying the Nested
propagation but in fact no nested calls are made. This will be fixed for
the Spring 1.2 release for SqlServer and Oracle which support nested
transactions. Also note, that changing of isolation levels on a
per-method basis is also scheduled for the Spring 1.2 release since it
requires detailed command text metadata for each dbprovider. Please
check the forums for news on when this feature will be introduced into
the nightly builds.

If you specify an exception type for 'NoRollbackFor' the action
taken is to commit the work that has been done in the database up to the
point where the exception occurred. The exception is still propagated
out to the calling code.

The ReadOnly boolean is a hint to the data access technology to
enable read-only optimizations. This currently has no effect in Spring's
ADO.NET framework. If you would like to enable read-only optimizations
in ADO.NET this is generally done via the 'Mode=Read' or
'Mode=Read-Only" options in the connection string. Check your database
provider for more information. In the case of NHibernate the flush mode
is set to Never when a new Session is created for the
transaction.

Throwing exceptions to indicate failure and assuming success is an
easier and less invasive programming model than performing the same task
Programatically - ContextUtil.MyTransactionVote or
TransactionScope.Complete. The rollback options are a means to influence
the outcome of the transaction based on the exception type which adds an
extra degree of flexibility.

Having any exception trigger a rollback has similar behavior as
applying the AutoComplete attribute available when using .NET Enterprise
Services. The difference with AutoComplete is that using AutoComplete is
also coupled to the lifetime of the ServicedComponent since it sets
ContextUtil.DeactivateOnReturn to true. For a stateless DAO layer this
is not an issue but it could be in other scenarios. Spring's
transactional aspect does not affect the lifetime of your object.

17.5.5. Declarative Transactions using AutoProxy

if you choose not to use the transaction namespace for declarative
transaction management then you can use 'lower level' object definitions
to configure declarative transactions. This approach was shown in the
first example. The use of
Spring's autoproxy functionality defines criteria to select a collection
of objects to create a transactional AOP proxy. There are two AutoProxy
classes that you can use,
ObjectNameAutoProxyCreator and
DefaultAdvisorAutoProxyCreator. If you are using
the new transaction namespace support you do not need to configure these
objects as a DefaultAdvisorAutoProxyCreator is created 'under the
covers' while parsing the transaction namespace elements

The ObjectNameAutoProxyCreator is useful when you would like to
create transactional proxies for many objects. The definitions for the
TransactionInterceptor and associated attributes is done once. When
you add new objects to your configuration file that need to be proxies
you only need to add them to the list of object referenced in the
ObjectNameAutoProxyCreator. Here is an example showing its use. Look
in the section that use ProxyFactoryObject for the declaration of the
transactionInterceptor.

This is a commonly used way to configure declarative
transactions since it enables you to refer to the transaction
attribute as the pointcut to use for the transactional advice for any
object definition defined in the IoC container. An example of this
configuration approach was shown in Chapter 5.

17.5.6. Declarative Transactions using
TransactionProxyFactoryObject

The TransactionProxyFactoryObject is easier to use than a
ProxyFactoryObject for most cases since the transaction interceptor and
transaction attributes are properties of this object. This removes the
need to declare them as separate objects. Also, unlike the case with the
ProxyFactoryObject, you do not have to give fully qualified method
names, just the normal 'short' method name. Wild card matching on the
method name is also allowed, which in practice helps to enforce a common
naming convention for the methods of your DAOs. The example from chapter
5 is shown here using a TransactionProxyFactoryObject.

Note the use of an inner object definition for the target which
will make it impossible to obtain an unproxied reference to the
TestObjectManager.

As can be seen in the above definition, the TransactionAttributes
property holds a collection of name/value pairs. The key of each pair is
a method or methods (a * wildcard ending is optional) to apply
transactional semantics to. Note that the method name is not qualified
with a package name, but rather is considered relative to the class of
the target object being wrapped. The value portion of the name/value
pair is the TransactionAttribute itself that needs to be applied. When
specifying it as a string value as in this example, it's in String
format as defined by TransactionAttributeConverter. This format
is:

Note that the only mandatory portion of the string is the
propagation setting. The default transactions semantics which apply are
as follows:

Exception Handling: All exceptions thrown trigger a
rollback.

Transactions are read/write

Isolation Level:
TransactionDefinition.ISOLATION_DEFAULT

Timeout: TransactionDefinition.TIMEOUT_DEFAULT

Multiple rollback rules can be specified here, comma-separated. A
- prefix forces rollback; a + prefix specifies commit. Under the covers
the IDictionary of name value pairs will be converted to an instance of
NameMatchTransactionAttributeSource

The string used for PROPAGATION_NAME are those defined on the
Spring.Transaction.TransactionPropagation enumeration, namely Required,
Supports, Mandatory, RequiresNew, NotSupported, Never, Nested. The
string used for ISOLATION_NAME are those defined on the
System.Data.IsolationLevel enumberateion, namely ReadCommitted,
ReadUncommitted, RepeatableRead, Serializable.

The TransactionProxyFactoryObject allows you to set optional "pre"
and "post" advice, for additional interception behavior, using the
"PreInterceptors" and "PostInterceptors" properties. Any number of pre
and post advices can be set, and their type may be Advisor (in which
case they can contain a pointcut), MethodInterceptor or any advice type
supported by the current Spring configuration (such as ThrowsAdvice,
AfterReturningAdvice or BeforeAdvice, which are supported by default.)
These advices must support a shared-instance model. If you need
transactional proxying with advanced AOP features such as stateful
mixins, it's normally best to use the generic ProxyFactoryObject, rather
than the TransactionProxyFactoryObject convenience proxy creator.

17.5.7. Concise proxy definitions

Using abstract object definitions in conjunction with a
TransactionProxyFactoryObject provides you a more concise means to reuse
common configuration information instead of duplicating it over and over
again with a definition of a TransactionProxyFactoryObject per object.
Objects that are to be proxied typically have the same pattern of method
names, Save*, Find*, etc. This commonality can be placed in an abstract
object definition, which other object definitions refer to and change
only the configuration information that is different. An abstract object
definition is shown below

17.5.8. Declarative Transactions using ProxyFactoryObject

Using the general ProxyFactoryObject to declare transactions gives
you a great deal of control over the proxy created since you can specify
additional advice, such as for logging or performance. Based on the
example shown previously a sample configuration using ProxyFactoryObject
is shown below

The ProxyFactoryObject will create a proxy for the Target, i.e. a
TestObjectManager instance. An inner object definition could also have
been used such that it would make it impossible to obtain an unproxied
object from the container. The interceptor name refers to the following
definition.

All but the propagation behavior are optional. The + and - are
used in front of the name of an exception. Minus indicates to rollback
if the exception is thrown, the Plus indicates to commit if the
exception is thrown.

17.6. Programmatic transaction management

Spring provides two means of programmatic transaction
management:

Using the TransactionTemplate

Using a
IPlatformTransactionManager
implementation directly

These are located in the Spring.Transaction.Support namespace. If
you are going to use programmatic transaction management, the Spring team
generally recommends the first approach (i.e. Using the
TransactionTemplate)

17.6.1. Using the TransactionTemplate

The TransactionTemplate adopts the same approach as other Spring
templates such as AdoTemplate and
HibernateTemplate. It uses a callback approach,
to free application code from having to do the boilerplate acquisition
and release of resources, and results in code that is intention driven,
in that the code that is written focuses solely on what the developer
wants to do. Granted that the using construct of System.Transaction
alleviates much of this. One key difference with the approach taken with
the TransactionTemplate is that a commit is assumed - throwing an
exception triggers a rollback instead of using the TransactionScope API
to commit or rollback. This also allows for the use of rollback rules,
that is a commit can still occur for exceptions of certain types.

Note

As you will immediately see in the examples that follow, using
the TransactionTemplate absolutely couples you to
Spring's transaction infrastructure and APIs. Whether or not
programmatic transaction management is suitable for your development
needs is a decision that you will have to make yourself.

Application code that must execute in a transaction context looks
like this. You, as an application developer, will write a
ITransactionCallback implementation (typically expressed as an anonymous
delegate) that will contain all of the code that you need to have
execute in the context of a transaction. You will then pass an instance
of your custom ITransactionCallback to the Execute(..) method exposed on
the TransactionTemplate. Note that the
ITransactionCallback can be used to
return a value:

This code example is specific to .NET 2.0 since it uses anonymous
delegates, which provides a particularly elegant means to invoke a
callback function as local variables can be referred to inside the
delegate, i.e. userId. In this case the
ITransactionStatus was not exposed in the
delegate (delegate can infer the signature to use), but one could also
obtain a reference to the
ITransactionStatus instance and set the
RollbackOnly property to trigger a rollback - or
alternatively throw an exception. This is shown below

Application classes wishing to use the
TransactionTemplate must have access to a
IPlatformTransactionManager (which will
typically be supplied to the class via dependency injection). It is easy
to unit test such classes with a mock or stub
IPlatformTransactionManager.

17.6.1.1. Specifying transaction settings

Transaction settings such as the propagation mode, the isolation
level, the timeout, and so forth can be set on the
TransactionTemplate either programmatically or
in configuration. TransactionTemplate instances
by default have the default transactional settings. Find below an
example of programmatically customizing the transactional settings for
a specific TransactionTemplate.

Find below an example of defining a
TransactionTemplate with some custom
transactional settings, using Spring XML configuration. The
'sharedTransactionTemplate' can then be injected
into as many services as are required.

Finally, instances of the
TransactionTemplate class are threadsafe, in
that instances do not maintain any conversational state.
TransactionTemplate instances do however
maintain configuration state, so while a number of classes may choose
to share a single instance of a
TransactionTemplate, if a class needed to use a
TransactionTemplate with different settings
(for example, a different isolation level), then two distinct
TransactionTemplate instances would need to be
created and used.

17.6.2. Using the PlatformTransactionManager

You can also use the PlatformTransactionManager directly to manage
your transaction. Simply pass the implementation of the
PlatformTransactionManager you're using to your object via a object
reference through standard Dependency Injection techniques. Then, using
the TransactionDefinition and ITransactionStatus objects, you can
initiate transactions, rollback and commit.

Programmatic transaction management is usually a good idea only if
you have a small number of transactional operations. For example, if you
have a web application that require transactions only for certain update
operations, you may not want to set up transactional proxies using Spring
or any other technology. In this case, using the TransactionTemplate may
be a good approach. On the other hand, if your application has numerous
transactional operations, declarative transaction management is usually
worthwhile. It keeps transaction management out of business logic, and is
not difficult to configure in Spring.

17.8. Transaction lifecycle and status information

You can query the status of the current Spring managed transaction
with the class TransactionSynchronizationManager.
Typical application code should not need to rely on using this class but
in some cases it is convenient to receive events around the lifecycle of
the transaction, i.e. before committing, after committing.
TransactionSynchronizationManager provides a method
to register a callback object that is informed on all significant stages
in the transaction lifecycle. Note that you can register for lifecycle
call back information for any of the transaction managers you use, be it
NHibernate or local ADO.NET transactions.

The method to register a callback with the
TransactionSynchronizationManager is