| | + title | Ref. /chapter[1]/title[1] |
| Original | Traduction | Transaction management |
| sect1
| | + title | Ref. /chapter[1]/sect1[1]/title[1] |
| Original | Traduction | The Spring transaction abstraction |
|
| + para | Ref. /chapter[1]/sect1[1]/para[1] |
| Original | Traduction | Spring provides a consistent abstraction for transaction management.
This abstraction is one of the most important of Spring's abstractions,
and delivers the following benefits:
| + para | Ref. /chapter[1]/sect1[1]/para[1]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | Provides a consistent programming model across different
transaction APIs such as JTA, JDBC, Hibernate, iBATIS Database Layer
and JDO. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[1]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Provides a simpler, easier to use, API for programmatic
transaction management than most of these transaction APIs |
|
| + para | Ref. /chapter[1]/sect1[1]/para[1]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | Integrates with the Spring data access abstraction |
|
| + para | Ref. /chapter[1]/sect1[1]/para[1]/itemizedlist[1]/listitem[4]/para[1] |
| Original | Traduction | Supports Spring declarative transaction management |
|
|
|
| + para | Ref. /chapter[1]/sect1[1]/para[2] |
| Original | Traduction | Traditionally, J2EE developers have had two choices for transaction
management: to use global or
local transactions. Global transactions are managed
by the application server, using JTA. Local transactions are
resource-specific: for example, a transaction associated with a JDBC
connection. This choice had profound implications. Global transactions
provide the ability to work with multiple transactional resources. (It's
worth noting that most applications use a single transaction resource)
With local transactions, the application server is not involved in
transaction management, and cannot help ensure correctness across multiple
resources. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[3] |
| Original | Traduction | Global transactions have a significant downside. Code needs to use
JTA: a cumbersome API to use (partly due to its exception model).
Furthermore, a JTA UserTransaction normally needs to be
obtained from JNDI: meaning that we need to use both
JNDI and JTA to use JTA. Obviously all use of global transactions limits
the reusability of application code, as JTA is normally only available in
an application server environment. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[4] |
| Original | Traduction | The preferred way to use global transactions was via EJB
CMT (Container Managed
Transaction): a form of declarative
transaction management (as distinguished from programmatic transaction management). EJB CMT
removes the need for transaction-related JNDI lookups--although of course
the use of EJB itself necessitates the use of JNDI. It removes most--not
all--need to write Java code to control transactions. The significant
downside is that CMT is (obviously) tied to JTA and an application server
environment; and that it's only available if we choose to implement
business logic in EJBs, or at least behind a transactional EJB facade. The
negatives around EJB in general are so great that this is not an
attractive proposition, when there are alternatives for declarative
transaction management. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[5] |
| Original | Traduction | Local transactions may be easier to use, but also have significant
disadvantages: They cannot work across multiple transactional resources,
and tend to invade the programming model. For example, code that manages
transactions using a JDBC connection cannot run within a global JTA
transaction. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[6] |
| Original | Traduction | Spring resolves these problems. It enables application developers to
use a consistent programming model in any
environment. You write your code once, and it can benefit from
different transaction management strategies in different environments.
Spring provides both declarative and programmatic transaction management.
Declarative transaction management is preferred by most users, and
recommended in most cases. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[7] |
| Original | Traduction | With programmatic transaction management developers work with the
Spring transaction abstraction, which can run over any underlying
transaction infrastructure. With the preferred declarative model
developers typically write little or no code related to transaction
management, and hence don't depend on Spring's or any other transaction
API. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[2]/title[1] |
| Original | Traduction | Transaction strategies |
|
| + para | Ref. /chapter[1]/sect1[2]/para[1] |
| Original | Traduction | The key to the Spring transaction abstraction is the notion of a
transaction strategy. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[2] |
| Original | Traduction | This is captured in the
org.springframework.transaction.PlatformTransactionManager
interface, shown below: |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/para[3]/programlisting[1] |
| Original | Traduction | public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
} |
|
| + para | Ref. /chapter[1]/sect1[2]/para[4] |
| Original | Traduction | This is primarily an SPI interface, although it can be used
programmatically. Note that in keeping with Spring's philosophy, this is
an interface. Thus it can easily be mocked or stubbed
if necessary. Nor is it tied to a lookup strategy such as JNDI:
PlatformTransactionManager implementations are defined like any other
object in a Spring IoC container. This benefit alone makes this a
worthwhile abstraction even when working with JTA: transactional code can
be tested much more easily than if it directly used JTA. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[5] |
| Original | Traduction | In keeping with Spring's philosophy,
TransactionException is unchecked. Failures of the
transaction infrastructure are almost invariably fatal. In rare cases
where application code can recover from them, the application developer
can still choose to catch and handle
TransactionException. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[6] |
| Original | Traduction | The getTransaction() method returns a
TransactionStatus object, depending on a
TransactionDefinition parameter. The returned
TransactionStatus might represent a new or existing
transaction (if there was a matching transaction in the current call
stack). |
|
| + para | Ref. /chapter[1]/sect1[2]/para[7] |
| Original | Traduction | As with J2EE transaction contexts, a
TransactionStatus is associated with a thread of execution. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[8] |
| Original | Traduction | The TransactionDefinition interface
specifies: |
|
| + para | Ref. /chapter[1]/sect1[2]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | Transaction 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? |
|
| + para | Ref. /chapter[1]/sect1[2]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Transaction 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 running in the existing
transaction (the most common case); or suspending the existing
transaction and creating a new transaction. Spring offers the
transaction propagation options familiar from EJB CMT. |
|
| + para | Ref. /chapter[1]/sect1[2]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | Transaction timeout: How long
this transaction may run before timing out (automatically being rolled
back by the underlying transaction infrastructure). |
|
| + para | Ref. /chapter[1]/sect1[2]/itemizedlist[1]/listitem[4]/para[1] |
| Original | Traduction | 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
Hibernate). |
|
| + para | Ref. /chapter[1]/sect1[2]/para[9] |
| Original | Traduction | These settings reflect standard concepts. If necessary, please refer
to a resource discussing transaction isolation levels and other core
transaction concepts: Understanding such core concepts is essential to
using Spring or any other transaction management solution. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[10] |
| Original | Traduction | The TransactionStatus interface provides a simple
way for transactional code to control transaction execution and query
transaction status. The concepts should be familiar, as they are common to
all transaction APIs: |
|
| + para | Ref. /chapter[1]/sect1[2]/para[11] |
| Original | Traduction | | + programlisting | Ref. /chapter[1]/sect1[2]/para[11]/programlisting[1] |
| Original | Traduction | public interface TransactionStatus {
boolean isNewTransaction();
void setRollbackOnly();
boolean isRollbackOnly();
} |
| However Spring transaction management is used, defining the
PlatformTransactionManager implementation is essential.
In good Spring fashion, this important definition is made using Inversion
of Control. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[12] |
| Original | Traduction | PlatformTransactionManager implementations normally require
knowledge of the environment in which they work: JDBC, JTA, Hibernate
etc. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[13] |
| Original | Traduction | The following examples from
dataAccessContext-local.xml from Spring's jPetStore sample application show how a local
PlatformTransactionManager implementation can be defined. This will work
with JDBC. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[14] |
| Original | Traduction | We must define a JDBC DataSource, and then use the Spring
DataSourceTransactionManager, giving it a reference to the
DataSource. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/para[15]/programlisting[1] |
| Original | Traduction | <bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
<property name="url"><value>${jdbc.url}</value></property>
<property name="username"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
</bean> |
|
| + para | Ref. /chapter[1]/sect1[2]/para[16] |
| Original | Traduction | The PlatformTransactionManager definition will look like
this: |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/para[17]/programlisting[1] |
| Original | Traduction | <bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref local="dataSource"/></property>
</bean> |
|
| + para | Ref. /chapter[1]/sect1[2]/para[18] |
| Original | Traduction | If we use JTA, as in the dataAccessContext-jta.xml
file from the same sample application, we need to use a
container DataSource, obtained via JNDI, and a JtaTransactionManager
implementation. The JtaTransactionManager doesn't need to know about the
DataSource, or any other specific resources, as it will use the
container's global transaction management. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[19] |
| Original | Traduction | | + programlisting | Ref. /chapter[1]/sect1[2]/para[19]/programlisting[1] |
| Original | Traduction | <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>jdbc/jpetstore</value></property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/> |
| We
can use Hibernate local transactions easily, as shown in the following
examples from the Spring PetClinic sample
application. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[20] |
| Original | Traduction | In this case, we need to define a Hibernate LocalSessionFactory,
which application code will use to obtain Hibernate Sessions. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[21] |
| Original | Traduction | The DataSource bean definition will be similar to one of the above
examples, and is not shown. (If it's a container DataSource it should be
non-transactional as Spring, rather than the container, will manage
transactions.) |
|
| + para | Ref. /chapter[1]/sect1[2]/para[22] |
| Original | Traduction | The "transactionManager" bean in this case is of class
HibernateTransactionManager. In the same way as the
DataSourceTransactionManager needs a reference to the DataSource, the
HibernateTransactionManager needs a reference to the session
factory. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/para[23]/programlisting[1] |
| Original | Traduction | <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="mappingResources">
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean> |
|
| + para | Ref. /chapter[1]/sect1[2]/para[24] |
| Original | Traduction | With Hibernate and JTA transactions we could simply use the
JtaTransactionManager as with JDBC or any other resource strategy. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/para[25]/programlisting[1] |
| Original | Traduction | <bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/> |
|
| + para | Ref. /chapter[1]/sect1[2]/para[26] |
| Original | Traduction | Note that this is identical to JTA configuration for any resource,
as these are global transactions, which can enlist any transactional
resource. |
|
| + remark | Ref. /chapter[1]/sect1[2]/remark[1] |
| Original | Traduction | In all these cases, application code won't need to change at all.
We can change how transactions are managed merely by changing
configuration, even if that change means moving from local to global
transactions or vice versa. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[27] |
| Original | Traduction | When not using global transactions, you do need to follow one
special coding convention. Fortunately this is very simple. You need to
obtain connection or session resources in a special way, to allow the
relevant PlatformTransactionManager implementation to track connection
usage, and apply transaction management as necessary. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[28] |
| Original | Traduction | For example, if using JDBC, you should not call the
getConnection() method on a DataSource, but must use
the Spring
org.springframework.jdbc.datasource.DataSourceUtils
class as follows: |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/programlisting[1] |
| Original | Traduction | Connection conn = DataSourceUtils.getConnection(dataSource); |
|
| + para | Ref. /chapter[1]/sect1[2]/para[29] |
| Original | Traduction | This has the added advantage that any
SQLException will be wrapped in a Spring
CannotGetJdbcConnectionException--one of Spring's
hierarchy of unchecked DataAccessExceptions. This gives you more
information than can easily be obtained from the
SQLException, and ensures portability across databases:
even across different persistence technologies. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[30] |
| Original | Traduction | This will work fine without Spring transaction management, so you
can use it whether or not you are using Spring for transaction
management. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[31] |
| Original | Traduction | Of course, once you've used Spring's JDBC support or Hibernate
support, you won't want to use DataSourceUtils or the
other helper classes, because you'll be much happier working via the
Spring abstraction than directly with the relevant APIs. For example, if
you use the Spring JdbcTemplate or jdbc.object package to simplify your
use of JDBC, correct connection retrieval happens behind the scenes and
you won't need to write any special code. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[3]/title[1] |
| Original | Traduction | Programmatic transaction management |
|
| + para | Ref. /chapter[1]/sect1[3]/para[1] |
| Original | Traduction | Spring provides two means of programmatic transaction
management: |
|
| + para | Ref. /chapter[1]/sect1[3]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | Using the TransactionTemplate |
|
| + para | Ref. /chapter[1]/sect1[3]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Using a PlatformTransactionManager
implementation directly |
|
| + para | Ref. /chapter[1]/sect1[3]/para[2] |
| Original | Traduction | We generally recommend the first approach. |
|
| + para | Ref. /chapter[1]/sect1[3]/para[3] |
| Original | Traduction | The second approach is similar to using the JTA
UserTransaction API (although exception handling is
less cumbersome). |
| sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[1]/title[1] |
| Original | Traduction | Using the TransactionTemplate |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[1] |
| Original | Traduction | The TransactionTemplate adopts the same
approach as other Spring templates such as
JdbcTemplate and
HibernateTemplate. It uses a callback approach, to
free application code from the working of acquiring and releasing
resources. (No more try/catch/finally.) Like other templates, a
TransactionTemplate is threadsafe. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[2] |
| Original | Traduction | Application code that must execute in a transaction context looks
like this. Note that the TransactionCallback can be
used to return a value: |
|
| + programlisting | Ref. /chapter[1]/sect1[3]/sect2[1]/para[3]/programlisting[1] |
| Original | Traduction | Object result = tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
}); |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[4] |
| Original | Traduction | If there's no return value, use a
TransactionCallbackWithoutResult like this: |
|
| + programlisting | Ref. /chapter[1]/sect1[3]/sect2[1]/para[5]/programlisting[1] |
| Original | Traduction | tt.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
}); |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[6] |
| Original | Traduction | Code within the callback can roll the transaction back by calling
the setRollbackOnly() method on the
TransactionStatus object. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[7] |
| Original | Traduction | Application classes wishing to use the
TransactionTemplate must have access to a
PlatformTransactionManager: usually exposed as a JavaBean property or as
a constructor argument. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[8] |
| Original | Traduction | It's easy to unit test such classes with a mock or stub
PlatformTransactionManager. There's no JNDI lookup or
static magic here: it's a simple interface. As usual, you can use Spring
to simplify your unit testing. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[2]/title[1] |
| Original | Traduction | Using the PlatformTransactionManager |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[2]/para[1] |
| Original | Traduction | You can also use the
org.springframework.transaction.PlatformTransactionManager
directly to manage your transaction. Simply pass the implementation of
the PlatformTransactionManager you're using to your bean via a bean
reference. Then, using the TransactionDefinition and
TransactionStatus objects you can initiate
transactions, rollback and commit. |
|
| + programlisting | Ref. /chapter[1]/sect1[3]/sect2[2]/para[2]/programlisting[1] |
| Original | Traduction | DefaultTransactionDefinition def = new DefaultTransactionDefinition()
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try {
// execute your business logic here
} catch (MyException ex) {
transactionManager.rollback(status);
throw ex;
}
transactionManager.commit(status); |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[4]/title[1] |
| Original | Traduction | Declarative transaction management |
|
| + para | Ref. /chapter[1]/sect1[4]/para[1] |
| Original | Traduction | Spring also offers declarative transaction management. This is
enabled by Spring AOP. |
|
| + remark | Ref. /chapter[1]/sect1[4]/remark[1] |
| Original | Traduction | 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. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[2] |
| Original | Traduction | It may be helpful to begin by considering EJB CMT and explaining the
similarities and differences with Spring declarative transaction
management. The basic approach is similar: It's possible to specify
transaction behavior (or lack of it) down to individual methods. It's
possible to make a setRollbackOnly() call within a
transaction context if necessary. The differences are: |
|
| + para | Ref. /chapter[1]/sect1[4]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | Unlike EJB CMT, which is tied to JTA, Spring declarative
transaction management works in any environment. It can work with
JDBC, JDO, Hibernate or other transactions under the covers, with
configuration changes only. |
|
| + para | Ref. /chapter[1]/sect1[4]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Spring enables declarative transaction management to be applied
to any POJO, not just special classes such as EJBs. |
|
| + para | Ref. /chapter[1]/sect1[4]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | Spring offers declarative rollback rules: a
feature with no EJB equivalent, which we'll discuss below. Rollback
can be controlled declaratively, not merely programmatically. |
|
| + para | Ref. /chapter[1]/sect1[4]/itemizedlist[1]/listitem[4]/para[1] |
| Original | Traduction | Spring gives you an opportunity to customize transactional
behavior, using AOP. For example, if you want to insert custom
behavior in the case of transaction rollback, you can. You can also
add arbitrary advice, along with the transactional advice. With EJB
CMT, you have no way to influence the container's transaction
management other than setRollbackOnly(). |
|
| + para | Ref. /chapter[1]/sect1[4]/itemizedlist[1]/listitem[5]/para[1] |
| Original | Traduction | Spring does not support propagation of transaction contexts
across remote calls, as do high-end application servers. If you need
this feature, we recommend that you use EJB. However, don't use this
feature lightly. Normally we don't want transactions to span remote
calls. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[3] |
| Original | Traduction | The concept of rollback rules is important: they enable us to
specify which exceptions (and throwables) should cause automatic roll
back. We specify this declaratively, in configuration, not in Java code.
So, while we can still call setRollbackOnly() on the
TransactionStatus object to roll the current
transaction back programmatically, most often we can specify a rule that
MyApplicationException should always result in roll
back. 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. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[4] |
| Original | Traduction | While the EJB default behavior is for the EJB container to
automatically roll back the transaction on a system
exception (usually a runtime exception), EJB CMT does not roll
back the transaction automatically on an application
exception (checked exception other than
java.rmi.RemoteException). While the Spring default
behavior for declarative transaction management follows EJB convention
(roll back is automatic only on unchecked exceptions), it's often useful
to customize this. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[5] |
| Original | Traduction | On our benchmarks, the performance of Spring declarative transaction
management exceeds that of EJB CMT. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[6] |
| Original | Traduction | The usual way of setting up transactional proxying in Spring is via
the TransactionProxyFactoryBean. We need a target object to wrap in a
transactional proxy. The target object is normally a POJO bean definition.
When we define the TransactionProxyFactoryBean, we must supply a reference
to the relevant PlatformTransactionManager, and transaction attributes. Transaction attributes
contain the transaction definitions, discussed above. Consider the
following sample: |
|
| + programlisting | Ref. /chapter[1]/sect1[4]/para[7]/programlisting[1] |
| Original | Traduction | <!-- this example is in verbose form, see note later about concise
for multiple proxies! -->
<!-- the target bean to wrap transactionally -->
<bean id="petStoreTarget">
...
</bean>
<bean id="petStore"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="target"><ref bean="petStoreTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean> |
|
| + para | Ref. /chapter[1]/sect1[4]/para[8] |
| Original | Traduction | The transactional proxy will implement the interfaces of the target:
in this case, the bean with id petStoreTarget. (Using CGLIB it's possible
to transactionally proxy a target class. Set the "proxyTargetClass" property
to true for this. It will happen automatically if the target doesn't
implement any interfaces. In general, of course, we want to program to
interfaces rather than classes.) It's possible (and usually a good idea)
to restrict the transactional proxy to proxying only specific target
interfaces, using the proxyInterfaces property. It's also possible to
customize the behavior of a TransactionProxyFactoryBean via several
properties inherited from
org.springframework.aop.framework.ProxyConfig, and
shared with all AOP proxy factories. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[9] |
| Original | Traduction | The transactionAttributes here are set using a Properties format
defined in the
org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource
class. The mapping from method name, including wildcards, should be fairly
intuitive. Note that the value for the insert* mapping contains a rollback
rule. Adding -MyCheckedException here specifies that if
the method throws MyCheckedException or any subclasses,
the transaction will automatically be rolled back. Multiple rollback rules
can be specified here, comma-separated. A - prefix forces rollback; a +
prefix specifies commit. (This allows commit even on unchecked exceptions,
if you really know what you're doing!) |
|
| + para | Ref. /chapter[1]/sect1[4]/para[10] |
| Original | Traduction | The TransactionProxyFactoryBean allows you to set
"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,
AfterReturningtAdvice 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
org.springframework.aop.framework.ProxyFactoryBean,
rather than the TransactionProxyFactoryBean convenience
proxy creator. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[11] |
| Original | Traduction | It's also possible to set up autoproxying: that is, to configure the
AOP framework so that classes are automatically proxied without needing
individual proxy definitions. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[12] |
| Original | Traduction | Please see the chapter on AOP for more information and
examples. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[13] |
| Original | Traduction | Note: Using TransactionProxyFactoryBean
definitions in the form above can seem overly verbose when many almost
identical transaction proxies need to be created. You will almost always
want to take advantage of parent and child bean definitions, along with
inner bean definitions, to significantly reduce the verbosity of your
transaction proxy definitions, as described in . |
|
| + remark | Ref. /chapter[1]/sect1[4]/remark[2] |
| Original | Traduction | You don't need to be an AOP expert--or indeed, to know much at all
about AOP--to use Spring's declarative transaction management effectively.
However, if you do want to become a "power user" of Spring AOP, you will
find it easy to combine declarative transaction management with powerful
AOP capabilities. |
| sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[1]/title[1] |
| Original | Traduction | BeanNameAutoProxyCreator,
another declarative approach |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1] |
| Original | Traduction | TransactionProxyFactoryBean is very useful,
and gives you full control when wrapping objects with a transactional
proxy. Used with parent/child bean definitions and inner beans holding
the target, it is generally the best choice for transactional wrapping.
In the case that you need to wrap a number of beans in a completely
identical fashion (for example, a boilerplate, 'make all methods
transactional', using a BeanFactoryPostProcessor
called BeanNameAutoProxyCreator can offer an
alternative approach which can end up being even less verbose for this
simplified use case. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[2] |
| Original | Traduction | To recap, once the ApplicationContext has read its initialization
information, it instantiates any beans within it which implement the
BeanPostProcessor interface, and gives them a
chance to post-process all other beans in the ApplicationContext. So
using this mechanism, a properly configured
BeanNameAutoProxyCreator can be used to
postprocess any other beans in the ApplicationContext (recognizing them
by name), and wrap them with a transactional proxy. The actual
transaction proxy produced is essentially identical to that produced by
the use of TransactionProxyFactoryBean, so will
not be discussed further. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[3] |
| Original | Traduction | Let us consider a sample configuration: |
|
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[1]/para[4]/programlisting[1] |
| Original | Traduction | <!-- Transaction Interceptor set up to do PROPAGATION_REQUIRED on all methods -->
<bean id="matchAllWithPropReq"
class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
<property name="transactionAttribute"><value>PROPAGATION_REQUIRED</value></property>
</bean>
<bean id="matchAllTxInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributeSource"><ref bean="matchAllWithPropReq"/></property>
</bean>
<!-- One BeanNameAutoProxyCreator handles all beans where we want all methods to use
PROPAGATION_REQUIRED -->
<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref local="matchAllTxInterceptor"/>
<idref bean="hibInterceptor"/>
</list>
</property>
<property name="beanNames">
<list>
<idref local="core-services-applicationControllerSevice"/>
<idref local="core-services-deviceService"/>
<idref local="core-services-authenticationService"/>
<idref local="core-services-packagingMessageHandler"/>
<idref local="core-services-sendEmail"/>
<idref local="core-services-userService"/>
</list>
</property>
</bean> |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[5] |
| Original | Traduction | Assuming that we already have a
TransactionManager instance in our
ApplicationContext, the first thing we need to do is create a
TransactionInterceptor instance to use. The
TransactionInterceptor decides which methods to
intercept based on a TransactionAttributeSource
implementing object passed to it as a property. In this case, we want to
handle the very simple case of matching all methods. This is not
necessarily the most efficient approach, but it's very quick to set up,
because we can use the special pre-defined
MatchAlwaysTransactionAttributeSource, which
simply matches all methods. If we wanted to be more specific, we could
use other variants such as
MethodMapTransactionAttributeSource,
NameMatchTransactionAttributeSource, or
AttributesTransactionAttributeSource. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[6] |
| Original | Traduction | Now that we have the transaction interceptor, we simply feed it to
a BeanNameAutoProxyCreator instance we define,
along with the names of 6 beans in the ApplicationContext that we want
to wrap in an identical fashion. As you can see, the net result is
significantly less verbose than it would have been to wrap 6 beans
identically with TransactionProxyFactoryBean. Wrapping a 7th bean would
add only one more line of config. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[7] |
| Original | Traduction | You may notice that we are able to apply multiple interceptors. In
this case, we are also applying a
HibernateInterceptor we have previously defined
(bean id=hibInterceptor), which will manage
Hibernate Sessions for us. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[8] |
| Original | Traduction | There is one thing to keep in mind, with regards to bean naming,
when switching back and forth between the use of
TransactionProxyFactoryBean, and
BeanNameAutoProxyCreator. For the former, if the
target bean is not defined as an inner bean, you normally give the
target bean you want to wrap an id similar in form to
myServiceTarget, and then give the proxy object an
id of myService; then all users of the wrapped
object simply refer to the proxy, i.e. myService.
(These are just sample naming conventions, the point is that the target
object has a different name than the proxy, and both are available from
the ApplicationContext). However, when using
BeanNameAutoProxyCreator, you name the target
object something like myService. Then, when
BeanNameAutoProxyCreator postprocesses the target
object and create the proxy, it causes the proxy to be inserted into the
Application context under the name of the original bean. From that point
on, only the proxy (the wrapped object) is available from the
ApplicationContext. When using TransactionProxyFactoryBean with the
target specified as an inner bean, this naming issue is not a concern,
since the inner bean is not normally given a name. |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[5]/title[1] |
| Original | Traduction | Choosing between programmatic and declarative transaction
management |
|
| + para | Ref. /chapter[1]/sect1[5]/para[1] |
| Original | Traduction | 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. Using the TransactionTemplate may be a good
approach. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[2] |
| Original | Traduction | On the other hand, if your applications 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. Using Spring, rather than EJB CMT, the
configuration cost of declarative transaction management is greatly
reduced. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[6]/title[1] |
| Original | Traduction | Do you need an application server for transaction
management? |
|
| + para | Ref. /chapter[1]/sect1[6]/para[1] |
| Original | Traduction | Spring's transaction management capabilities--and especially its
declarative transaction management--significantly changes traditional
thinking as to when a J2EE application requires an application
server. |
|
| + para | Ref. /chapter[1]/sect1[6]/para[2] |
| Original | Traduction | In particular, you don't need an application server just to have
declarative transactions via EJB. In fact, even if you have an application
server with powerful JTA capabilities, you may well decide that Spring
declarative transactions offer more power and a much more productive
programming model than EJB CMT. |
|
| + para | Ref. /chapter[1]/sect1[6]/para[3] |
| Original | Traduction | You need an application server's JTA capability only if you need to
enlist multiple transactional resources. Many applications don't face this
requirement. For example, many high-end applications use a single, highly
scalable, database such as Oracle 9i RAC. |
|
| + para | Ref. /chapter[1]/sect1[6]/para[4] |
| Original | Traduction | Of course you may need other application server capabilities such as
JMS and JCA. However, if you need only JTA, you could also consider an
open source JTA add-on such as JOTM. (Spring integrates with JOTM out of
the box.) However, as of early 2004, high-end application servers provide
more robust support for XA transactions. |
|
| + para | Ref. /chapter[1]/sect1[6]/para[5] |
| Original | Traduction | The most important point is that with Spring you can
choose when to scale your application up to a full-blown application
server. Gone are the days when the only alternative to using
EJB CMT or JTA was to write coding using local transactions such as those
on JDBC connections, and face a hefty rework if you ever needed that code
to run within global, container-managed transactions. With Spring only
configuration needs to change: your code doesn't. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[7]/title[1] |
| Original | Traduction | Common problems |
|
| + para | Ref. /chapter[1]/sect1[7]/para[1] |
| Original | Traduction | Developers should take care to use the correct
PlatformTransactionManager
implementation for their requirements. |
|
| + para | Ref. /chapter[1]/sect1[7]/para[2] |
| Original | Traduction | It's important to understand how the Spring transaction abstraction
works with JTA global transactions. Used properly, there is no conflict
here: Spring merely provides a simplifying, portable abstraction. |
|
| + para | Ref. /chapter[1]/sect1[7]/para[3] |
| Original | Traduction | If you are using global transactions, you must
use the Spring
org.springframework.transaction.jta.JtaTransactionManager
for all your for all your transactional operations. Otherwise Spring will
attempt to perform local transactions on resources such as container
DataSources. Such local transactions don't make sense, and a good
application server will treat them as errors. |
|
| |
|