Diferencia entre revisiones de «Transacciones Con Spring»
(→Anotaciones) |
(→Configuración) |
||
(No se muestra una edición intermedia de otro usuario) | |||
Línea 15: | Línea 15: | ||
Spring 2.x introduce una forma extensible de agregar tags en los archivos de configuración. Así, existen distintas extensiones que se pueden agregar a la configuración de Spring, ampliando la funcionalidad. | Spring 2.x introduce una forma extensible de agregar tags en los archivos de configuración. Así, existen distintas extensiones que se pueden agregar a la configuración de Spring, ampliando la funcionalidad. | ||
− | Esta configuración se agrega en el encabezado de cada XML de Spring, e indica | + | Esta configuración se agrega en el encabezado de cada XML de Spring, e indica qué schemas utiliza dicho archivo. |
Para la configuración de transacciones usaremos los schemas "aop" y "tx". El encabezado de nuestro archivo entonces queda: | Para la configuración de transacciones usaremos los schemas "aop" y "tx". El encabezado de nuestro archivo entonces queda: | ||
Línea 143: | Línea 143: | ||
*[[Spring Framework]] | *[[Spring Framework]] | ||
*[[Spring Test]] (para transacciones en los tests) | *[[Spring Test]] (para transacciones en los tests) | ||
+ | *[[Transaction Manager en Weblogic]] | ||
*[http://static.springframework.org/spring/docs/2.0.x/reference/transaction.html Manual de Spring: Capítulo 9] | *[http://static.springframework.org/spring/docs/2.0.x/reference/transaction.html Manual de Spring: Capítulo 9] | ||
* [http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction-declarative-annotations Uso de @Transactional] | * [http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction-declarative-annotations Uso de @Transactional] |
Revisión actual del 11:43 13 ene 2011
Spring Framework permite configurar transacciones en forma declarativa. De esta forma, la manipulación de transacciones queda establecida en archivos de configuración, sin generar ningún impacto en el código.
Contenido
Transacciones en Spring
En Spring cualquier bean puede ser transaccional. La transaccionalidad se declara por método. En ningún momento se utiliza explícitamente JTA, sino que Spring inyecta funcionalidad de acuerdo a ciertas reglas (similares a las de EJB).
Rollback de transacciones
Por default, una transacción falla solamente cuando el método tira una unchecked exception (las que no se declaran, heredan de RuntimeException). Cuando una transacción falla, se realiza un rollback.
Noten que, por lo tanto, las excepciones de negocio no realizan un rollback (declaradas en el "throws" del método). Es decir, pese a que se lance una excepción de negocio, igualmente se hará un commit de la transacción. Este comportamiento puede cambiarse en la configuración, como veremos más adelante.
Configuración
Spring 2.x introduce una forma extensible de agregar tags en los archivos de configuración. Así, existen distintas extensiones que se pueden agregar a la configuración de Spring, ampliando la funcionalidad.
Esta configuración se agrega en el encabezado de cada XML de Spring, e indica qué schemas utiliza dicho archivo.
Para la configuración de transacciones usaremos los schemas "aop" y "tx". El encabezado de nuestro archivo entonces queda:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> </beans>
Pointcuts y Advices
Con ese encabezado estamos entonces listos para configurar transacciones. Lo que haremos será declarar todos los objetos que necesitamos sean transaccionales, y luego aplicaremos transacciones a todo un grupo de objetos.
Es decir, la configuración de transacciones ya no será "por objeto", sino mucho más amplia (por ejemplo, "todos las clases del paquete business").
Crearemos entonces un Pointcut que indicará qué clases serán interceptadas para agregar transacción, al cual le agregaremos un Advice. El advice indicará qué tipo de transacción tendrán las clases interceptadas por el pointcut.
En la práctica, esto es realmente muy simple:
<tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="buscar*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice>
<aop:config> <aop:pointcut id="businessOperation" expression="execution(* com.dosideas.business.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="businessOperation"/> </aop:config>
<bean id="business.PaisBo" class="com.dosideas.business.impl.PaisBoImpl"/> <bean id="business.ProvinciaBo" class="com.dosideas.business.impl.ProvinciaBoImpl"/>
<bean id="business.LocalidadBo" class="com.dosideas.business.impl.LocalidadBoImpl"/>
Todas las clases de "business.impl" serán interceptadas, y se les aplicará el advice "txAdvice". Este advice indica que los métodos que comienzan con "buscar" son de sólo lectura, y el resto serán transaccionales (de tipo "REQUIRED", que es el default).
Es posible tambien tener mas de un pointcut:
<aop:pointcut id="businessOperation" expression="execution(* com.dosideas.business.*.*(..)) and !execution(* com.dosideas.business.Cliente.guardar(..))"/>
<aop:pointcut id="businessOperationGuardarCliente" expression="execution(* com.dosideas.business.Cliente.guardar(..))"/>
El pointcut businessOperation referencia a todas las clases de business.impl, salvo el metodo guardar de la clase com.dosideas.business.Cliente (que es referenciado por el pointcut businessOperationGuardarCliente).
Noten entonces que la definición de transaccionalidad se escribe una única vez (o por paquete, o como sea más cómodo), y los los BO se declaran luego normalmente.
Configurando un Advice
Como sabemos, las transacciones realizan un rollback ante una RuntimeException, aunque esto es posible cambiarlo:
<tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="buscar*" read-only="true" rollback-for="ObjetoNoEncontradoException"/> <tx:method name="*"/> </tx:attributes> </tx:advice>
Por otro lado, también es posible cambiar la propagación de las transacciones para determiandos métodos:
<tx:advice id="noTxAdvice"> <tx:attributes> <tx:method name="*" propagation="NEVER"/> </tx:attributes> </tx:advice>
Anotaciones
Es posible configurar las transacciones usando anotaciones en las clases en vez de declarando pointcuts en un XML. De esta manera, la declaración de la transacción queda más cerca del código que afecta.
Para esto es necesario agregar el siguiente tag al XML de Spring, para indicarle que habilite el soporte de transacciones por anotaciones:
<tx:annotation-driven transaction-manager="transactionManager"/>
El atributo "transaction-manager" referencia al Transaction Manager en uso.
Luego, podemos usar la anotación @Transactional para declarar que un método (o todos los métodos de una clase) es transaccional:
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo);
}
También es posible pasarle parámetros a la anotación @Transactional para configurar detalles de la transacción. Por ejemplo, la siguiente clase declara a todos sus métodos como de sólo-lectura, excepto el método updateFoo():
@Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo buscarFoo(long codigo) { ... }
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) public void updateFoo(Foo foo) {... }
}
Ver también
- Transacciones En Java
- Concepto De Transaccion
- Spring Framework
- Spring Test (para transacciones en los tests)
- Transaction Manager en Weblogic
- Manual de Spring: Capítulo 9
- Uso de @Transactional