SPRNET-1299 - Move older ways of configuring transaction management, using HibernateTemplate, to a 'Classic Spring Usage' section
This commit is contained in:
538
doc/reference/src/classic-spring.xml
Normal file
538
doc/reference/src/classic-spring.xml
Normal file
@@ -0,0 +1,538 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<appendix id="classic-spring">
|
||||
<title>Classic Spring Usage</title>
|
||||
|
||||
<para>This appendix discusses some classic Spring usage patterns as a
|
||||
reference for developers maintaining legacy Spring applications. These usage
|
||||
patterns no longer reflect the recommended way of using these features and
|
||||
the current recommended usage is covered in the respective sections of the
|
||||
reference manual.</para>
|
||||
|
||||
<section>
|
||||
<title>Classic Hibernate Usage</title>
|
||||
|
||||
<para>For the currently recommended usage patterns for NHibernate see
|
||||
<xref linkend="orm-hibernate" /></para>
|
||||
|
||||
<section xml:id="orm-hibernate-template">
|
||||
<title>The <literal>HibernateTemplate</literal></title>
|
||||
|
||||
<para>The basic programming model for templating looks as follows for
|
||||
methods that can be part of any custom data access object or business
|
||||
service. There are no restrictions on the implementation of the
|
||||
surrounding object at all, it just needs to provide a Hibernate
|
||||
<literal>SessionFactory</literal>. It can get the latter from anywhere,
|
||||
but preferably as an object reference from a Spring IoC container - via
|
||||
a simple <methodname>SessionFactory</methodname> property setter. The
|
||||
following snippets show a DAO definition in a Spring container,
|
||||
referencing the above defined <literal>SessionFactory</literal>, and an
|
||||
example for a DAO method implementation.</para>
|
||||
|
||||
<programlisting language="myxml"><objects>
|
||||
|
||||
<object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
|
||||
<property name="SessionFactory" ref="MySessionFactory"/>
|
||||
</object>
|
||||
|
||||
</objects></programlisting>
|
||||
|
||||
<para />
|
||||
|
||||
<programlisting language="csharp">public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
public ISessionFactory SessionFactory
|
||||
{
|
||||
set { hibernateTemplate = new HibernateTemplate(value); }
|
||||
}
|
||||
|
||||
public Customer SaveOrUpdate(Customer customer)
|
||||
{
|
||||
hibernateTemplate.SaveOrUpdate(customer);
|
||||
return customer;
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>The <literal>HibernateTemplate</literal> class provides many
|
||||
methods that mirror the methods exposed on the Hibernate
|
||||
<literal>Session</literal> interface, in addition to a number of
|
||||
convenience methods such as the one shown above. If you need access to
|
||||
the <literal>Session</literal> to invoke methods that are not exposed on
|
||||
the <literal>HibernateTemplate</literal>, you can always drop down to a
|
||||
callback-based approach like so.</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
public ISessionFactory SessionFactory
|
||||
{
|
||||
set { hibernateTemplate = new HibernateTemplate(value); }
|
||||
}
|
||||
|
||||
public Customer SaveOrUpdate(Customer customer)
|
||||
{
|
||||
return HibernateTemplate.Execute(
|
||||
delegate(ISession session)
|
||||
{
|
||||
// do whatever you want with the session....
|
||||
session.SaveOrUpdate(customer);
|
||||
return customer;
|
||||
}) as Customer;
|
||||
}
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>Using the anonymous delegate is particularly convenient when you
|
||||
would otherwise be passing various method parameter calls to the
|
||||
interface based version of this callback. Furthermore, when using
|
||||
generics, you can avoid the typecast and write code like the
|
||||
following</para>
|
||||
|
||||
<programlisting language="csharp">IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>(
|
||||
delegate(ISession session)
|
||||
{
|
||||
return session.CreateQuery("from Supplier s were s.Code = ?")
|
||||
.SetParameter(0, code)
|
||||
.List<Supplier>();
|
||||
});</programlisting>
|
||||
|
||||
<para>where code is a variable in the surrounding block, accessible
|
||||
inside the anonymous delegate implementation.</para>
|
||||
|
||||
<para>A callback implementation effectively can be used for any
|
||||
Hibernate data access. <literal>HibernateTemplate</literal> will ensure
|
||||
that <literal>Session</literal> instances are properly opened and
|
||||
closed, and automatically participate in transactions. The template
|
||||
instances are thread-safe and reusable, they can thus be kept as
|
||||
instance variables of the surrounding class. For simple single step
|
||||
actions like a single Find, Load, SaveOrUpdate, or Delete call,
|
||||
<literal>HibernateTemplate</literal> offers alternative convenience
|
||||
methods that can replace such one line callback implementations.
|
||||
Furthermore, Spring provides a convenient
|
||||
<literal>HibernateDaoSupport</literal> base class that provides a
|
||||
<methodname>SessionFactory</methodname> property for receiving a
|
||||
<literal>SessionFactory</literal> and for use by subclasses. In
|
||||
combination, this allows for very simple DAO implementations for typical
|
||||
requirements:</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
|
||||
{
|
||||
public Customer SaveOrUpdate(Customer customer)
|
||||
{
|
||||
HibernateTemplate.SaveOrUpdate(customer);
|
||||
return customer;
|
||||
}
|
||||
}</programlisting>
|
||||
</section>
|
||||
|
||||
<section xml:id="orm-hibernate-daos">
|
||||
<title>Implementing Spring-based DAOs without callbacks</title>
|
||||
|
||||
<para>As an alternative to using Spring's
|
||||
<literal>HibernateTemplate</literal> to implement DAOs, data access code
|
||||
can also be written in a more traditional fashion, without wrapping the
|
||||
Hibernate access code in a callback, while still respecting and
|
||||
participating in Spring's generic <literal>DataAccessException</literal>
|
||||
hierarchy. The <literal>HibernateDaoSupport</literal> base class offers
|
||||
methods to access the current transactional <literal>Session</literal>
|
||||
and to convert exceptions in such a scenario; similar methods are also
|
||||
available as static helpers on the
|
||||
<literal>SessionFactoryUtils</literal> class. Note that such code will
|
||||
usually pass '<literal>false</literal>' as the value of the
|
||||
<methodname>DoGetSession(..)</methodname> method's
|
||||
'<literal>allowCreate</literal>' argument, to enforce running within a
|
||||
transaction (which avoids the need to close the returned
|
||||
<literal>Session</literal>, as its lifecycle is managed by the
|
||||
transaction). Asking for the</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateProductDao : HibernateDaoSupport, IProductDao {
|
||||
|
||||
public Customer SaveOrUpdate(Customer customer)
|
||||
{
|
||||
ISession session = DoGetSession(false);
|
||||
session.SaveOrUpdate(customer);
|
||||
return customer;
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>This code will <emphasis>not</emphasis> translate the Hibernate
|
||||
exception to a generic <literal>DataAccessException</literal>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Classic Declarative Transaction Configurations</title>
|
||||
|
||||
<section xml:id="classic-tx-advisor">
|
||||
<title>Declarative Transaction Configuration using
|
||||
DefaultAdvisorAutoProxyCreator</title>
|
||||
|
||||
<para>Using the DefaultAdvisorAutoProxyCreator to configure declarative
|
||||
transactions 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. The configuration to create a
|
||||
transactional proxy for the manager class shown in the chapter on
|
||||
transaction management is shown below.</para>
|
||||
|
||||
<programlisting language="myxml"> <!-- The rest of the config file is common no matter how many objects you add -->
|
||||
<!-- that you would like to have declarative tx management applied to -->
|
||||
|
||||
<object id="autoProxyCreator"
|
||||
type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop">
|
||||
</object>
|
||||
|
||||
<object id="transactionAdvisor"
|
||||
type="Spring.Transaction.Interceptor.TransactionAttributeSourceAdvisor, Spring.Data">
|
||||
<property name="TransactionInterceptor" ref="transactionInterceptor"/>
|
||||
</object>
|
||||
|
||||
|
||||
<!-- Transaction Interceptor -->
|
||||
<object id="transactionInterceptor"
|
||||
type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
|
||||
<property name="TransactionManager" ref="transactionManager"/>
|
||||
<property name="TransactionAttributeSource" ref="attributeTransactionAttributeSource"/>
|
||||
</object>
|
||||
|
||||
<object id="attributeTransactionAttributeSource"
|
||||
type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data">
|
||||
</object>
|
||||
</programlisting>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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 <xref
|
||||
linkend="objects-factory-xml-import" /> for more information.</para>
|
||||
|
||||
<para>The classes and their roles in this configuration fragment are
|
||||
listed below</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>TransactionInterceptor</literal> is the AOP advice
|
||||
responsible for performing transaction management
|
||||
functionality.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>TransactionAttributeSourceAdvisor</literal> 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.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>AttributesTransactionAttributeSource</literal> is an
|
||||
implementation of the <literal>ITransactionAttributeSource</literal>
|
||||
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
|
||||
<literal>ITransactionAttributeSource</literal> interface. This
|
||||
example shows the use of the implementation
|
||||
<literal>Spring.Transaction.Interceptor.AttributesTransactionAttributeSource</literal>
|
||||
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
|
||||
<literal>ITransactionAttributeSource</literal> available are
|
||||
<literal>MatchAlwaysTransactionAttributeSource</literal>,
|
||||
<literal>NameMatchTransactionAttributeSource</literal>, or
|
||||
<literal>MethodMapTransactionAttributeSource</literal>.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>MatchAlwaysTransactionAttributeSource</literal>
|
||||
is configured with a ITransactionAttribute instance that is
|
||||
applied to all methods. The shorthand string representation,
|
||||
i.e. PROPAGATION_REQUIRED can be used</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>AttributesTransactionAttributeSource</literal> :
|
||||
Use a standard. .NET attributes to specify the transactional
|
||||
information. See <literal>TransactionAttribute</literal> class
|
||||
for more information.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>NameMatchTransactionAttributeSource</literal>
|
||||
allows ITransactionAttributes to be matched by method name. The
|
||||
NameMap IDictionary property is used to specify the mapping. For
|
||||
example</para>
|
||||
|
||||
<programlisting language="myxml"><object name="nameMatchTxAttributeSource" type="Spring.Transaction.Interceptor.NameMatchTransactionAttributeSource, Spring.Data"
|
||||
<property name="NameMap">
|
||||
<dictionary>
|
||||
<entry key="Execute" value="PROPAGATION_REQUIRES_NEW, -ApplicationException"/>
|
||||
<entry key="HandleData" value="PROPAGATION_REQUIRED, -DataHandlerException"/>
|
||||
<entry key="Find*" value="ISOLATION_READUNCOMMITTED, -DataHandlerException"/>
|
||||
</dictionary>
|
||||
</property>
|
||||
|
||||
</object></programlisting>
|
||||
|
||||
<para>Key values can be prefixed and/or suffixed with wildcards
|
||||
as well as include the full namespace of the containing
|
||||
class.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>MethodMapTransactionAttributeSource</literal> :
|
||||
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.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>DefaultAdvisorAutoProxyCreator</literal>: looks for
|
||||
Advisors in the context, and automatically creates proxy objects
|
||||
which are the transactional wrappers</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Refer to the following section for a more convenient way to
|
||||
achieve the same goal of declarative transaction management using
|
||||
attributes.</para>
|
||||
</section>
|
||||
<section xml:id="classic-tx-txproxyfactoryobject">
|
||||
<title>Declarative Transactions using TransactionProxyFactoryObject</title>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<programlisting language="myxml">
|
||||
<object id="testObjectManager"
|
||||
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
|
||||
|
||||
<property name="PlatformTransactionManager" ref="adoTransactionManager"/>
|
||||
<property name="Target">
|
||||
<object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
|
||||
<property name="TestObjectDao" ref="testObjectDao"/>
|
||||
</object>
|
||||
</property>
|
||||
<property name="TransactionAttributes">
|
||||
<name-values>
|
||||
<add key="Save*" value="PROPAGATION_REQUIRED"/>
|
||||
<add key="Delete*" value="PROPAGATION_REQUIRED"/>
|
||||
</name-values>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
</programlisting>
|
||||
|
||||
<para>Note the use of an inner object definition for the target which
|
||||
will make it impossible to obtain an unproxied reference to the
|
||||
TestObjectManager.</para>
|
||||
|
||||
<para>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:</para>
|
||||
|
||||
<para><literal>PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2</literal></para>
|
||||
|
||||
<para>Note that the only mandatory portion of the string is the
|
||||
propagation setting. The default transactions semantics which apply are
|
||||
as follows:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Exception Handling: All exceptions thrown trigger a
|
||||
rollback.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Transactions are read/write</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Isolation Level:
|
||||
TransactionDefinition.ISOLATION_DEFAULT</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Timeout: TransactionDefinition.TIMEOUT_DEFAULT</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>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
|
||||
<literal>NameMatchTransactionAttributeSource</literal></para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="classic-using-abstract-objectdefs">
|
||||
<title>Concise proxy definitions</title>
|
||||
|
||||
<para>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</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="txProxyTemplate" abstract="true"
|
||||
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
|
||||
|
||||
<property name="PlatformTransactionManager" ref="adoTransactionManager"/>
|
||||
|
||||
<property name="TransactionAttributes">
|
||||
<name-values>
|
||||
<add key="Save*" value="PROPAGATION_REQUIRED"/>
|
||||
<add key="Delete*" value="PROPAGATION_REQUIRED"/>
|
||||
</name-values>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
|
||||
<para>Subsequent definitions can refer to this 'base' configuration as
|
||||
shown below</para>
|
||||
|
||||
<programlisting language="myxml"><object id="testObjectManager" parent="txProxyTemplate">
|
||||
<property name="Target">
|
||||
<object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
|
||||
<property name="TestObjectDao" ref="testObjectDao"/>
|
||||
</object>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
</section>
|
||||
|
||||
<section xml:id="classic-tx-proxyfactoryobject">
|
||||
<title>Declarative Transactions using ProxyFactoryObject</title>
|
||||
|
||||
<para>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</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="testObjectManagerTarget" type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
|
||||
<property name="TestObjectDao" ref="testObjectDao"/>
|
||||
</object>
|
||||
|
||||
<object id="testObjectManager" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
|
||||
|
||||
<property name="Target" ref="testObjectManagerTarget"/>
|
||||
<property name="ProxyInterfaces">
|
||||
<value>Spring.Data.ITestObjectManager</value>
|
||||
</property>
|
||||
<property name="InterceptorNames">
|
||||
<value>transactionInterceptor</value>
|
||||
</property>
|
||||
|
||||
</object></programlisting>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="transactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
|
||||
|
||||
<property name="TransactionManager" ref="adoTransactionManager"/>
|
||||
|
||||
<!-- note do not have converter from string to this property type registered -->
|
||||
<property name="TransactionAttributeSource" ref="methodMapTransactionAttributeSource"/>
|
||||
</object>
|
||||
|
||||
<object name="methodMapTransactionAttributeSource"
|
||||
type="Spring.Transaction.Interceptor.MethodMapTransactionAttributeSource, Spring.Data">
|
||||
<property name="MethodMap">
|
||||
<dictionary>
|
||||
<entry key="Spring.Data.TestObjectManager.SaveTwoTestObjects, Spring.Data.Integration.Tests"
|
||||
value="PROPAGATION_REQUIRED"/>
|
||||
<entry key="Spring.Data.TestObjectManager.DeleteTwoTestObjects, Spring.Data.Integration.Tests"
|
||||
value="PROPAGATION_REQUIRED"/>
|
||||
</dictionary>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
|
||||
<para>The transaction options for each method are specified using a
|
||||
dictionary containing the class name + method name, assembly as the key
|
||||
and the value is of the form</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><Propagation Behavior>, <Isolation Level>,
|
||||
<ReadOnly>, -Exception, +Exception</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>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.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</appendix>
|
||||
@@ -55,6 +55,7 @@
|
||||
<!ENTITY xsd-configuration SYSTEM "xsd-configuration.xml">
|
||||
<!ENTITY xml-custom SYSTEM "xml-custom.xml">
|
||||
<!ENTITY xsd SYSTEM "xsd.xml">
|
||||
<!ENTITY classic-spring SYSTEM "classic-spring.xml">
|
||||
]>
|
||||
<book xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
@@ -65,7 +66,7 @@
|
||||
<title>The Spring.NET Framework</title>
|
||||
<subtitle>Reference Documentation</subtitle>
|
||||
<releaseinfo>Version 1.3.0</releaseinfo>
|
||||
<pubdate>Last Updated December 15, 2009 <ulink url="http://www.springframework.net/doc-latest/reference/html/index.html">(Latest documentation)</ulink></pubdate>
|
||||
<pubdate>Last Updated December 17, 2009 <ulink url="http://www.springframework.net/doc-latest/reference/html/index.html">(Latest documentation)</ulink></pubdate>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
@@ -452,8 +453,12 @@
|
||||
</part>
|
||||
|
||||
<!-- back matter -->
|
||||
&xsd-configuration;
|
||||
&xml-custom;
|
||||
&xsd;
|
||||
<part id="spring-appendices">
|
||||
<title>Appendices</title>
|
||||
&classic-spring;
|
||||
&xsd-configuration;
|
||||
&xml-custom;
|
||||
&xsd;
|
||||
</part>
|
||||
|
||||
</book>
|
||||
|
||||
@@ -591,155 +591,6 @@ public class HibernateCustomerDao : ICustomerDao {
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="orm-hibernate-template">
|
||||
<title>The <literal>HibernateTemplate</literal> for Hibernate
|
||||
1.2</title>
|
||||
|
||||
<para>The basic programming model for templating looks as follows for
|
||||
methods that can be part of any custom data access object or business
|
||||
service. There are no restrictions on the implementation of the
|
||||
surrounding object at all, it just needs to provide a Hibernate
|
||||
<literal>SessionFactory</literal>. It can get the latter from anywhere,
|
||||
but preferably as an object reference from a Spring IoC container - via
|
||||
a simple <methodname>SessionFactory</methodname> property setter. The
|
||||
following snippets show a DAO definition in a Spring container,
|
||||
referencing the above defined <literal>SessionFactory</literal>, and an
|
||||
example for a DAO method implementation.</para>
|
||||
|
||||
<programlisting language="myxml"><objects>
|
||||
|
||||
<object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
|
||||
<property name="SessionFactory" ref="MySessionFactory"/>
|
||||
</object>
|
||||
|
||||
</objects></programlisting>
|
||||
|
||||
<para></para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
public ISessionFactory SessionFactory
|
||||
{
|
||||
set { hibernateTemplate = new HibernateTemplate(value); }
|
||||
}
|
||||
|
||||
public Customer SaveOrUpdate(Customer customer)
|
||||
{
|
||||
hibernateTemplate.SaveOrUpdate(customer);
|
||||
return customer;
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>The <literal>HibernateTemplate</literal> class provides many
|
||||
methods that mirror the methods exposed on the Hibernate
|
||||
<literal>Session</literal> interface, in addition to a number of
|
||||
convenience methods such as the one shown above. If you need access to
|
||||
the <literal>Session</literal> to invoke methods that are not exposed on
|
||||
the <literal>HibernateTemplate</literal>, you can always drop down to a
|
||||
callback-based approach like so.</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
public ISessionFactory SessionFactory
|
||||
{
|
||||
set { hibernateTemplate = new HibernateTemplate(value); }
|
||||
}
|
||||
|
||||
public Customer SaveOrUpdate(Customer customer)
|
||||
{
|
||||
return HibernateTemplate.Execute(
|
||||
delegate(ISession session)
|
||||
{
|
||||
// do whatever you want with the session....
|
||||
session.SaveOrUpdate(customer);
|
||||
return customer;
|
||||
}) as Customer;
|
||||
}
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>Using the anonymous delegate is particularly convenient when you
|
||||
would otherwise be passing various method parameter calls to the
|
||||
interface based version of this callback. Furthermore, when using
|
||||
generics, you can avoid the typecast and write code like the
|
||||
following</para>
|
||||
|
||||
<programlisting language="csharp">IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>(
|
||||
delegate(ISession session)
|
||||
{
|
||||
return session.CreateQuery("from Supplier s were s.Code = ?")
|
||||
.SetParameter(0, code)
|
||||
.List<Supplier>();
|
||||
});</programlisting>
|
||||
|
||||
<para>where code is a variable in the surrounding block, accessible
|
||||
inside the anonymous delegate implementation.</para>
|
||||
|
||||
<para>A callback implementation effectively can be used for any
|
||||
Hibernate data access. <literal>HibernateTemplate</literal> will ensure
|
||||
that <literal>Session</literal> instances are properly opened and
|
||||
closed, and automatically participate in transactions. The template
|
||||
instances are thread-safe and reusable, they can thus be kept as
|
||||
instance variables of the surrounding class. For simple single step
|
||||
actions like a single Find, Load, SaveOrUpdate, or Delete call,
|
||||
<literal>HibernateTemplate</literal> offers alternative convenience
|
||||
methods that can replace such one line callback implementations.
|
||||
Furthermore, Spring provides a convenient
|
||||
<literal>HibernateDaoSupport</literal> base class that provides a
|
||||
<methodname>SessionFactory</methodname> property for receiving a
|
||||
<literal>SessionFactory</literal> and for use by subclasses. In
|
||||
combination, this allows for very simple DAO implementations for typical
|
||||
requirements:</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
|
||||
{
|
||||
public Customer SaveOrUpdate(Customer customer)
|
||||
{
|
||||
HibernateTemplate.SaveOrUpdate(customer);
|
||||
return customer;
|
||||
}
|
||||
}</programlisting>
|
||||
</section>
|
||||
|
||||
<section xml:id="orm-hibernate-daos">
|
||||
<title>Implementing Spring-based DAOs without HibernateTemplate in
|
||||
Hibernate 1.2</title>
|
||||
|
||||
<para>As an alternative to using Spring's
|
||||
<literal>HibernateTemplate</literal> to implement DAOs, data access code
|
||||
can also be written in a more traditional fashion, without wrapping the
|
||||
Hibernate access code in a callback, while still respecting and
|
||||
participating in Spring's generic <literal>DataAccessException</literal>
|
||||
hierarchy. The <literal>HibernateDaoSupport</literal> base class offers
|
||||
methods to access the current transactional <literal>Session</literal>
|
||||
and to convert exceptions in such a scenario; similar methods are also
|
||||
available as static helpers on the
|
||||
<literal>SessionFactoryUtils</literal> class. Note that such code will
|
||||
usually pass '<literal>false</literal>' as the value of the
|
||||
<methodname>DoGetSession(..)</methodname> method's
|
||||
'<literal>allowCreate</literal>' argument, to enforce running within a
|
||||
transaction (which avoids the need to close the returned
|
||||
<literal>Session</literal>, as its lifecycle is managed by the
|
||||
transaction). Asking for the</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateProductDao : HibernateDaoSupport, IProductDao {
|
||||
|
||||
public Customer SaveOrUpdate(Customer customer)
|
||||
{
|
||||
ISession session = DoGetSession(false);
|
||||
session.SaveOrUpdate(customer);
|
||||
return customer;
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>This code will <emphasis>not</emphasis> translate the Hibernate
|
||||
exception to a generic <literal>DataAccessException</literal>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="orm-hibernate-tx-declarative">
|
||||
<title>Declarative transaction demarcation</title>
|
||||
|
||||
@@ -439,16 +439,16 @@
|
||||
</emphasis>lightweight container.</remark>
|
||||
|
||||
<para>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.</para>
|
||||
Spring's aspect-oriented programming (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.</para>
|
||||
|
||||
<para>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:</para>
|
||||
<para>The 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 calling the <methodname>SetRollbackOnly()</methodname>
|
||||
method within a transaction context if necessary. Some of the highlights
|
||||
of Spring's declarative transaction management are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
@@ -482,20 +482,17 @@
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Note rollback rules as configured from XML are still under
|
||||
development.</para>
|
||||
|
||||
<para>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
|
||||
<literal>RollbackOnly</literal> on the
|
||||
declaratively, in configuration, not in code. So, although you can still
|
||||
call <methodname>SetRollbackOnly() </methodname>on the
|
||||
<literal>ITransactionStatus</literal> object to roll the current
|
||||
transaction back Programatically, most often we can specify a rule that
|
||||
transaction back, most often you 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
|
||||
significant advantage that business objects do not 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
|
||||
import any Spring transaction APIs or other Spring APIs. However, to
|
||||
rollback the transaction programmatically when using declarative
|
||||
transaction management, use the utility method</para>
|
||||
|
||||
<programlisting language="csharp">TransactionInterceptor.CurrentTransactionStatus.SetRollbackOnly();</programlisting>
|
||||
@@ -510,37 +507,26 @@
|
||||
<title>Understanding Spring's declarative transaction
|
||||
implementation</title>
|
||||
|
||||
<para>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.</para>
|
||||
<para>It is not sufficient to tell you simply to annotate your classes
|
||||
with the <literal>[Transaction]</literal> attribute, add the line
|
||||
(<literal><tx:attribute-driven/></literal>) to your configuration,
|
||||
and then expect you to understand how it all works. This section
|
||||
explains the inner workings of the Spring Framework's declarative
|
||||
transaction infrastructure in the event of transaction-related
|
||||
issues.</para>
|
||||
|
||||
<note>
|
||||
<para>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.</para>
|
||||
</note>
|
||||
|
||||
<para>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
|
||||
<literal>TransactionInterceptor</literal> in conjunction with an
|
||||
appropriate <literal>IPlatformTransactionManager</literal>
|
||||
<para>The most important concepts to grasp with regard to the Spring
|
||||
Framework's declarative transaction support are that this support is
|
||||
enabled via <link linkend="aop-proxy-mechanism">AOP proxies</link>, and
|
||||
that the transactional advice is driven by metadata (currently XML- or
|
||||
attribute-based). The combination of AOP with transactional metadata
|
||||
yields an AOP proxy that uses a
|
||||
<classname>TransactionInterceptor</classname> in conjunction with an
|
||||
appropriate <interfacename>IPlatformTransactionManager</interfacename>
|
||||
implementation to drive transactions around method invocations.</para>
|
||||
|
||||
<note>
|
||||
<para>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.</para>
|
||||
<para>Spring AOP is covered in <xref linkend="aop" /></para>
|
||||
</note>
|
||||
|
||||
<para>Conceptually, calling a method on a transactional proxy looks like
|
||||
@@ -551,96 +537,26 @@
|
||||
<imagedata fileref="images/tx.png"></imagedata>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>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</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>ProxyFactoryObject</literal>. The common properties
|
||||
to set are the reference to the object to proxy (the target object)
|
||||
and a reference to the transaction advice. See <xref
|
||||
linkend="aop-proxyfactoryobject" /> for more details.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>AutoProxy - Defines criteria to select a collection of objects
|
||||
to create a transactional AOP proxy.</para>
|
||||
|
||||
<para>The AutoProxy options are</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>ObjectNameAutoProxyCreator</literal> which
|
||||
specifies a collection of object names based on wildcard
|
||||
matching of object names. See <xref
|
||||
linkend="aop-nameautoproxy" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>DefaultAdvisorAutoProxyCreator</literal> which
|
||||
specifies one or more "advisors" i.e an object representing an
|
||||
aspect, including both an advice and a pointcut targeting it to
|
||||
specific joinpoints. See <xref
|
||||
linkend="aop-advisorautoproxy" /></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>There is also a convenience subclass of
|
||||
<literal>ProxyFactoryObject</literal>, namely
|
||||
<literal>TransactionProxyFactoryObject</literal>, that sets some common
|
||||
default values for the specific case of applying transactional
|
||||
advice.</para>
|
||||
|
||||
<para>The <literal>DefaultAdvisorAutoProxyCreator</literal> 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>
|
||||
<para>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.</para>
|
||||
</note></para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 xml:id="tx-firstexample">
|
||||
<title>A First Example</title>
|
||||
<title>Example of declarative transaction implementation</title>
|
||||
|
||||
<para>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
|
||||
<literal>ITestObjectManager</literal> 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.</para>
|
||||
have to worry about domain specific details. </para>
|
||||
|
||||
<note>
|
||||
<para>A QuickStart application for declarative transaction management
|
||||
is included in the Spring.NET distribution and is decribed <link
|
||||
linkend="tx-quickstart">here</link>.</para>
|
||||
</note>
|
||||
|
||||
<para>The <literal>ITestObjectManager</literal> 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.</para>
|
||||
|
||||
<programlisting language="csharp">public interface ITestObjectManager
|
||||
{
|
||||
@@ -657,14 +573,14 @@
|
||||
|
||||
// Fields/Properties ommited
|
||||
|
||||
[Transaction()]
|
||||
[Transaction]
|
||||
public void SaveTwoTestObjects(TestObject to1, TestObject to2)
|
||||
{
|
||||
TestObjectDao.Create(to1.Name, to1.Age);
|
||||
TestObjectDao.Create(to2.Name, to1.Age);
|
||||
}
|
||||
|
||||
[Transaction()]
|
||||
[Transaction]
|
||||
public void DeleteTwoTestObjects(string name1, string name2)
|
||||
{
|
||||
TestObjectDao.Delete(name1);
|
||||
@@ -773,8 +689,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
|
||||
|
||||
|
||||
<!-- The object that performs multiple data access operations -->
|
||||
<object id="testObjectManager"
|
||||
type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
|
||||
<object id="testObjectManager" type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
|
||||
<property name="TestObjectDao" ref="testObjectDao"/>
|
||||
</object>
|
||||
|
||||
@@ -783,144 +698,10 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
|
||||
|
||||
<para>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.</para>
|
||||
easily switch implementations of your DAO objects.</para>
|
||||
|
||||
<programlisting language="myxml"> <!-- The rest of the config file is common no matter how many objects you add -->
|
||||
<!-- that you would like to have declarative tx management applied to -->
|
||||
|
||||
<object id="autoProxyCreator"
|
||||
type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop">
|
||||
</object>
|
||||
|
||||
<object id="transactionAdvisor"
|
||||
type="Spring.Transaction.Interceptor.TransactionAttributeSourceAdvisor, Spring.Data">
|
||||
<property name="TransactionInterceptor" ref="transactionInterceptor"/>
|
||||
</object>
|
||||
|
||||
|
||||
<!-- Transaction Interceptor -->
|
||||
<object id="transactionInterceptor"
|
||||
type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
|
||||
<property name="TransactionManager" ref="transactionManager"/>
|
||||
<property name="TransactionAttributeSource" ref="attributeTransactionAttributeSource"/>
|
||||
</object>
|
||||
|
||||
<object id="attributeTransactionAttributeSource"
|
||||
type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data">
|
||||
</object>
|
||||
</programlisting>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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 <xref
|
||||
linkend="objects-factory-xml-import" /> for more information.</para>
|
||||
|
||||
<para>The classes and their roles in this configuration fragment are
|
||||
listed below</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>TransactionInterceptor</literal> is the AOP advice
|
||||
responsible for performing transaction management
|
||||
functionality.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>TransactionAttributeSourceAdvisor</literal> 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.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>AttributesTransactionAttributeSource</literal> is an
|
||||
implementation of the <literal>ITransactionAttributeSource</literal>
|
||||
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
|
||||
<literal>ITransactionAttributeSource</literal> interface. This
|
||||
example shows the use of the implementation
|
||||
<literal>Spring.Transaction.Interceptor.AttributesTransactionAttributeSource</literal>
|
||||
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
|
||||
<literal>ITransactionAttributeSource</literal> available are
|
||||
<literal>MatchAlwaysTransactionAttributeSource</literal>,
|
||||
<literal>NameMatchTransactionAttributeSource</literal>, or
|
||||
<literal>MethodMapTransactionAttributeSource</literal>.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>MatchAlwaysTransactionAttributeSource</literal>
|
||||
is configured with a ITransactionAttribute instance that is
|
||||
applied to all methods. The shorthand string representation,
|
||||
i.e. PROPAGATION_REQUIRED can be used</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>AttributesTransactionAttributeSource</literal> :
|
||||
Use a standard. .NET attributes to specify the transactional
|
||||
information. See <literal>TransactionAttribute</literal> class
|
||||
for more information.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>NameMatchTransactionAttributeSource</literal>
|
||||
allows ITransactionAttributes to be matched by method name. The
|
||||
NameMap IDictionary property is used to specify the mapping. For
|
||||
example</para>
|
||||
|
||||
<programlisting language="myxml"><object name="nameMatchTxAttributeSource" type="Spring.Transaction.Interceptor.NameMatchTransactionAttributeSource, Spring.Data"
|
||||
<property name="NameMap">
|
||||
<dictionary>
|
||||
<entry key="Execute" value="PROPAGATION_REQUIRES_NEW, -ApplicationException"/>
|
||||
<entry key="HandleData" value="PROPAGATION_REQUIRED, -DataHandlerException"/>
|
||||
<entry key="Find*" value="ISOLATION_READUNCOMMITTED, -DataHandlerException"/>
|
||||
</dictionary>
|
||||
</property>
|
||||
|
||||
</object></programlisting>
|
||||
|
||||
<para>Key values can be prefixed and/or suffixed with wildcards
|
||||
as well as include the full namespace of the containing
|
||||
class.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>MethodMapTransactionAttributeSource</literal> :
|
||||
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.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>DefaultAdvisorAutoProxyCreator</literal>: looks for
|
||||
Advisors in the context, and automatically creates proxy objects
|
||||
which are the transactional wrappers</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Refer to the following section for a more convenient way to
|
||||
achieve the same goal of declarative transaction management using
|
||||
attributes.</para>
|
||||
<para>The following section shows how to configure the declarative
|
||||
transactions using Spring's transaction namespace.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 xml:id="tx-namespace">
|
||||
@@ -1554,13 +1335,12 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
|
||||
|
||||
<para>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
|
||||
<link linkend="tx-firstexample">first example</link>. 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, <literal>ObjectNameAutoProxyCreator</literal>
|
||||
and <literal>DefaultAdvisorAutoProxyCreator</literal>. If you are using
|
||||
the new transaction namespace support you do not need to configure these
|
||||
to configure declarative transactions. 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, <literal>ObjectNameAutoProxyCreator</literal> and
|
||||
<literal>DefaultAdvisorAutoProxyCreator</literal>. 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</para>
|
||||
|
||||
@@ -1593,219 +1373,11 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
|
||||
<title>Creating transactional proxies with
|
||||
DefaultAdvisorAutoProxyCreator</title>
|
||||
|
||||
<para>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.</para>
|
||||
<para>This is not longer a common way to configure declarative
|
||||
transactions but is discussed in the "Classic Spring" appendiex <link
|
||||
linkend="classic-txadvisor">here</link>.</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<sect2 xml:id="tx-txproxyfactoryobject">
|
||||
<title>Declarative Transactions using
|
||||
TransactionProxyFactoryObject</title>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<programlisting language="myxml">
|
||||
<object id="testObjectManager"
|
||||
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
|
||||
|
||||
<property name="PlatformTransactionManager" ref="adoTransactionManager"/>
|
||||
<property name="Target">
|
||||
<object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
|
||||
<property name="TestObjectDao" ref="testObjectDao"/>
|
||||
</object>
|
||||
</property>
|
||||
<property name="TransactionAttributes">
|
||||
<name-values>
|
||||
<add key="Save*" value="PROPAGATION_REQUIRED"/>
|
||||
<add key="Delete*" value="PROPAGATION_REQUIRED"/>
|
||||
</name-values>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
</programlisting>
|
||||
|
||||
<para>Note the use of an inner object definition for the target which
|
||||
will make it impossible to obtain an unproxied reference to the
|
||||
TestObjectManager.</para>
|
||||
|
||||
<para>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:</para>
|
||||
|
||||
<para><literal>PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2</literal></para>
|
||||
|
||||
<para>Note that the only mandatory portion of the string is the
|
||||
propagation setting. The default transactions semantics which apply are
|
||||
as follows:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Exception Handling: All exceptions thrown trigger a
|
||||
rollback.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Transactions are read/write</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Isolation Level:
|
||||
TransactionDefinition.ISOLATION_DEFAULT</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Timeout: TransactionDefinition.TIMEOUT_DEFAULT</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>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
|
||||
<literal>NameMatchTransactionAttributeSource</literal></para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 xml:id="tx-using-abstract-objectdefs">
|
||||
<title>Concise proxy definitions</title>
|
||||
|
||||
<para>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</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="txProxyTemplate" abstract="true"
|
||||
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
|
||||
|
||||
<property name="PlatformTransactionManager" ref="adoTransactionManager"/>
|
||||
|
||||
<property name="TransactionAttributes">
|
||||
<name-values>
|
||||
<add key="Save*" value="PROPAGATION_REQUIRED"/>
|
||||
<add key="Delete*" value="PROPAGATION_REQUIRED"/>
|
||||
</name-values>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
|
||||
<para>Subsequent definitions can refer to this 'base' configuration as
|
||||
shown below</para>
|
||||
|
||||
<programlisting language="myxml"><object id="testObjectManager" parent="txProxyTemplate">
|
||||
<property name="Target">
|
||||
<object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
|
||||
<property name="TestObjectDao" ref="testObjectDao"/>
|
||||
</object>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 xml:id="tx-proxyfactoryobject">
|
||||
<title>Declarative Transactions using ProxyFactoryObject</title>
|
||||
|
||||
<para>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</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="testObjectManagerTarget" type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
|
||||
<property name="TestObjectDao" ref="testObjectDao"/>
|
||||
</object>
|
||||
|
||||
<object id="testObjectManager" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
|
||||
|
||||
<property name="Target" ref="testObjectManagerTarget"/>
|
||||
<property name="ProxyInterfaces">
|
||||
<value>Spring.Data.ITestObjectManager</value>
|
||||
</property>
|
||||
<property name="InterceptorNames">
|
||||
<value>transactionInterceptor</value>
|
||||
</property>
|
||||
|
||||
</object></programlisting>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="transactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
|
||||
|
||||
<property name="TransactionManager" ref="adoTransactionManager"/>
|
||||
|
||||
<!-- note do not have converter from string to this property type registered -->
|
||||
<property name="TransactionAttributeSource" ref="methodMapTransactionAttributeSource"/>
|
||||
</object>
|
||||
|
||||
<object name="methodMapTransactionAttributeSource"
|
||||
type="Spring.Transaction.Interceptor.MethodMapTransactionAttributeSource, Spring.Data">
|
||||
<property name="MethodMap">
|
||||
<dictionary>
|
||||
<entry key="Spring.Data.TestObjectManager.SaveTwoTestObjects, Spring.Data.Integration.Tests"
|
||||
value="PROPAGATION_REQUIRED"/>
|
||||
<entry key="Spring.Data.TestObjectManager.DeleteTwoTestObjects, Spring.Data.Integration.Tests"
|
||||
value="PROPAGATION_REQUIRED"/>
|
||||
</dictionary>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
|
||||
<para>The transaction options for each method are specified using a
|
||||
dictionary containing the class name + method name, assembly as the key
|
||||
and the value is of the form</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><Propagation Behavior>, <Isolation Level>,
|
||||
<ReadOnly>, -Exception, +Exception</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>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.</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="transaction-programmatic">
|
||||
|
||||
Reference in New Issue
Block a user