Para implementar transacciones en Spring usando configuración XML, primero se deben establecer el origen de datos y crear las instancias de los objetos de negocio. A continuación, se detalla el proceso y un ejemplo práctico.
Pasos de configuración
1. Definir el administrador de transacciones:
Se asume la disponibilidad de las bibliotecas necesarias: Spring Framework, C3P0, MySQL y AOP.
Archivo de propiedades de base de datos (database.properties):
public interface IProductoDao { void eliminar(String id); }
</div><div>```
package com.ejemplo.dao;
public interface IPedidoDao {
void eliminarPorProducto(String productoId);
}
public interface IProductoServicio { void eliminar(String id); }
</div>**Implementaciones de los DAO:**
<div>```
package com.ejemplo.daoimpl;
import org.springframework.jdbc.core.JdbcTemplate;
import com.ejemplo.dao.IProductoDao;
public class ProductoDao implements IProductoDao {
private JdbcTemplate plantillaJdbc;
public void setPlantillaJdbc(JdbcTemplate plantillaJdbc) {
this.plantillaJdbc = plantillaJdbc;
}
@Override
public void eliminar(String id) {
// Error simulado para probar rollback
if ("prod007".equals(id)) {
throw new RuntimeException("Falla en la operación");
}
String consulta = "DELETE FROM productos WHERE id = ?";
plantillaJdbc.update(consulta, id);
}
}
import org.springframework.jdbc.core.JdbcTemplate; import com.ejemplo.dao.IPedidoDao;
public class PedidoDao implements IPedidoDao { private JdbcTemplate plantillaJdbc;
public void setPlantillaJdbc(JdbcTemplate plantillaJdbc) {
this.plantillaJdbc = plantillaJdbc;
}
@Override
public void eliminarPorProducto(String productoId) {
String consulta = "DELETE FROM pedidos WHERE producto_id = ?";
plantillaJdbc.update(consulta, productoId);
}
}
</div>**Implementación del servicio de negocio:**
<div>```
package com.ejemplo.daoimpl;
import com.ejemplo.dao.IProductoDao;
import com.ejemplo.dao.IProductoServicio;
import com.ejemplo.dao.IPedidoDao;
public class ProductoServicio implements IProductoServicio {
private IProductoDao productoDao;
private IPedidoDao pedidoDao;
public void setProductoDao(IProductoDao productoDao) {
this.productoDao = productoDao;
}
public void setPedidoDao(IPedidoDao pedidoDao) {
this.pedidoDao = pedidoDao;
}
@Override
public void eliminar(String id) {
productoDao.eliminar(id);
pedidoDao.eliminarPorProducto(id);
}
}
<context:property-placeholder location="classpath:database.properties" />
<!-- Fuente de datos C3P0 -->
<bean id="miDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driver}" />
<property name="jdbcUrl" value="${db.url}" />
<property name="user" value="${db.usuario}" />
<property name="password" value="${db.clave}" />
<property name="minPoolSize" value="${pool.min}" />
<property name="maxPoolSize" value="${pool.max}" />
<property name="initialPoolSize" value="${pool.inicial}" />
</bean>
<!-- Plantilla JDBC -->
<bean id="plantillaJdbc" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="miDataSource" />
</bean>
<!-- Beans de acceso a datos -->
<bean id="productoDao" class="com.ejemplo.daoimpl.ProductoDao">
<property name="plantillaJdbc" ref="plantillaJdbc" />
</bean>
<bean id="pedidoDao" class="com.ejemplo.daoimpl.PedidoDao">
<property name="plantillaJdbc" ref="plantillaJdbc" />
</bean>
<!-- Servicio de negocio -->
<bean id="productoServicio" class="com.ejemplo.daoimpl.ProductoServicio">
<property name="productoDao" ref="productoDao" />
<property name="pedidoDao" ref="pedidoDao" />
</bean>
<!-- Configuración de transacciones -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="miDataSource" />
</bean>
<tx:advice id="consejoTx" transaction-manager="txManager">
<tx:attributes>
<tx:method name="eliminar" propagation="REQUIRED" />
<tx:method name="*" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice>
<!-- Punto de corte AOP -->
<aop:config>
<aop:pointcut id="puntoCorteServicio" expression="execution(* com.ejemplo.daoimpl.ProductoServicio.*(..))" />
<aop:advisor advice-ref="consejoTx" pointcut-ref="puntoCorteServicio" />
</aop:config>
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.ejemplo.dao.IProductoServicio;
public class PruebaTransaccion { public static void main(String[] args) { ApplicationContext contexto = new ClassPathXmlApplicationContext("app-context.xml"); IProductoServicio servicio = contexto.getBean("productoServicio", IProductoServicio.class); try { servicio.eliminar("prod007"); // Provoca excepción simulada } catch (Exception e) { System.out.println("Transacción revertida: " + e.getMessage()); } } }
</div>Al ejecutar la prueba, se genera una excepción de división por cero en la capa de DAO, lo que provoca el rollback de la transacción. Por lo tanto, los registros no se eliminan de la base de datos, confirmando que la configuración de transacciones está activa.