1. Spring’s transactional support
Spring’s transactional support consists of two main parts for managing transactions on beans that
are managed by the container:
■ Transactional synchronization —This manages resources used to handle transactions. This
mechanism is directly integrated into Spring’s data access support and is based on a transactional
context stored in a variable of type ThreadLocal.
■ Transaction demarcation —This allows you to apply transactions to application logic. Although an
API is available, Spring also provides features to declaratively apply them to Spring-managed beans
through AOP and annotations.
The key abstraction for this support is the PlatformTransactionManager interface, which provides a
contract for transaction demarcation. The following snippet shows the content of this interface:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition);
void commit(TransactionStatus status);
void rollback(TransactionStatus status);
}
In the PlatformTransactionManager interface, the getTransaction method allows you to initialize
and start a transaction. The commit method successfully finalizes a transaction; the rollback
one cancels it.
Implementations of this interface are provided for each data access implementation in Spring.
These implementations are commonly based on factories for the corresponding technology
(because they must be able to access resources to manage transactions), or, in the case of JTA,
on the Java transaction manager.
With respect to transaction propagation, Spring defaults to transactions being REQUIRED on
beans, which allows application components to participate in the current transaction or to
create it if it doesn’t exist. In addition, Spring introduces read-only transactions, which can help
improve performance in ORM tools.
You can configure transactions in Spring by following these steps:
■ Create and configure all your POJOs in the Spring container. They will correspond to abstractions
for data access, DAO entities, and business services.
■ Configure a transaction manager bean, whose implementation depends on the underlying
persistence technology.
■ Apply transactional behaviors to business services using either XML or transaction annotations.
Transaction configuration using AOP and XML:
<bean id="transactionManager" (...)>
(...)
</bean>
<aop:config>
<aop:advisor
pointcut="execution(* *..*ServiceImpl.*(..))"
advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*"/>
<tx:method name="update*"/>
<tx:method name="delete*"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
@Transactional
public interface ContactsService {
@Transactional(readOnly=true)
List<Contact> getContacts();
void addContact(Contact contact);
}
Another possibility is to use the Transactional annotation to specify transactional behavior
directly in interfaces and classes. Information specified on interfaces is automatically
used in corresponding implementations and can be overridden if necessary. The annotation
can be specified both at the class level or method level. At the class level, it provides global
configuration for all methods, which can then be overridden if another configuration is required.
Transactional annotation support isn’t activated by default and must be enabled through the
annotation-driven element of Spring’s tx namespace, as shown in the following snippet:
<bean id="transactionManager" (...)>
(...)
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
2. Using JPA transactions with Spring DM
As emphasized in the previous section, the central abstraction of Spring’s transactional
support is the PlatformTransactionManager. When using local transactions, the transaction
manager implementation depends on the underlying data access technology, whereas
for global transactions Spring provides a specific implementation that interacts with the
underlying JTA transaction manager (which is usually hosted by an application server).
We’ll describe here only the local transaction approach and use the annotation-driven
method of configuring transactions.
We can identify two use cases for configuring transaction management, depending on the
organization of bundles within an application:
■ Services and DAOs are in the same component. In this case, Spring’s transaction support can
be used as in regular Spring applications. The EntityManagerEntity entity, services, DAO, and
Spring transaction manager are all located in the same Spring container.
■ Services and DAOs are in different components. In this case, services, the EntityManagerEntity
entity, and the Spring transaction manager are located in different components. Because you
need a transaction manager to apply transactions to services, this must be registered as an
OSGi service. The service component is then able to reference and use it.
In the first use case, bundles are autonomous(自治的), containing both services and DAO entities,
and they embed their own transaction managers. Transactions are managed within these
components, and transactions are already applied to entities registered as OSGi services.
In the use case where services and DAOs are separated, the Spring transaction manager can be
provided as an OSGi service to a service component by the DAO component. In the service
component, this service is used to apply transactions to services.
The service for the Spring transaction manager is registered under the
PlatformTransactionManager interface, which is the root interface for all transaction managers
within Spring. That makes this service independent from the underlying data access technology.
<bean id="entityManagerFactory" class="(...)">
(...)
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<osgi:service ref="transactionManager"
interface="org.springframework.transaction.PlatformTransactionManager"/>
<osgi:reference id="transactionManager"
interface="org.springframework.transaction.PlatformTransactionManager"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
Import-Package: (...)
javax.persistence.spi;version="1.0.0",
org.aopalliance.aop;version="1.0",
org.springframework.aop;version="3.0.0.M1",
org.springframework.aop.framework;version="3.0.0.M1",
org.springframework.transaction.annotation;version="3.0.0.M1 "
We saw that Spring provides the Transactional annotation for describing transactional behavior. A
good practice consists of using this annotation on service interfaces. All the implementation classes
will then directly benefit from the definition of transactional behavior at the interface level.