transaction transacciones transaccional framework example driven data con annotation java spring transactions spring-transactions transactional

java - transacciones - transaction spring data



Spring @Transactional y herencia (3)

Tengo una clase DAO basada en genéricos, que es la base para todas las demás clases DAO en mi proyecto y contiene una funcionalidad común:

public class Dao<E> { private SessionFactory factory; public void setSessionFactory(SessionFactory factory) { this.factory = factory; } public E get(int id) { // .... } public void save(E entity) { // ... } public void delete(E entity) { // ... } }

En mi proyecto estoy usando múltiples fuentes de datos, apuntando a diferentes bases de datos, por lo tanto, tengo múltiples gestores de sesiones y transacciones:

<bean id="factory1" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="source1" /> </bean> <bean id="manager1" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="factory1" /> </bean> <bean id="factory2" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="source2" /> </bean> <bean id="manager2" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="factory2" /> </bean>

Ahora quiero crear un par de DAO que operen en diferentes bases de datos:

@Repository @Transactional("manager1") public class Dao1 extends Dao<Entity1> { @Overrides @Autowired @Qualifier("factory1") public void setSessionFactory(SessionFactory factory) { super.setSessionFactory(factory); } } @Repository @Transactional("manager2") public class Dao1 extends Dao<Entity2> { @Overrides @Autowired @Qualifier("factory2") public void setSessionFactory(SessionFactory factory) { super.setSessionFactory(factory); } }

pero el problema es que todos los métodos públicos de Dao no están cubiertos por @Transactional de las clases secundarias, por lo que no se produce ninguna gestión de transacciones. La única opción en la que puedo pensar es anular los métodos de clase padre, por lo que están definidos en clases heredadas y, por lo tanto, se encargan de @Transactional :

@Repository @Transactional("manager1") public class Dao1 extends Dao<Entity1> { @Overrides @Autowired @Qualifier("factory1") public void setSessionFactory(SessionFactory factory) { super.setSessionFactory(factory); } @Overrides public Entity1 get(int id) { return super.get(id); } @Overrides public void save(Entity1 entity) { super.save(entity); } @Overrides public void delete(Entity1 entity) { super.delete(entity); } }

Pero luego tendría que hacer esto en cada clase DAO, y el código estaría en todas partes igual ...

¿Hay una mejor manera de compartir la funcionalidad común en todas las clases y aún así tener todos los beneficios de la gestión declarativa de transacciones?


En lugar de agregar la anotación @Transactional todas partes, debe usar la gestión de transacciones basada en AOP como:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice>

Es una buena práctica usar transacciones en la capa de servicio.


¿Has intentado poner @Transaction en los métodos de la clase padre DAO?

public class Dao<E> { private SessionFactory factory; public void setSessionFactory(SessionFactory factory) { this.factory = factory; } @Transactional(readOnly = true) public E get(int id) { // .... } @Transactional public void save(E entity) { // ... } @Transactional public void delete(E entity) { // ... } }

De esta forma, cuando llame a save en DAO1, recuperará el nivel de clase @Transaction de la subclase (que especificará qué administrador de TX usar) y luego seleccionará el método @Transactional del método de guardado del padre.


En caso de que no te @Transactional la super clase también sería @Transactional , deberías poner la anotación en el super DAO. En caso de que le @Transactional , le sugiero que cree una clase que se extienda TransactionalDao que extenderá el DAO principal y será @Transactional y todos los DAO que deberían ser @Transactional también lo extenderán:

public class Dao<E> { private SessionFactory factory; public void setSessionFactory(SessionFactory factory) { this.factory = factory; } public E get(int id) { // .... } public void save(E entity) { // ... } public void delete(E entity) { // ... } } @Transactional public class TransactionalDao<E> extends Dao<E>{ private SessionFactory factory; public void setSessionFactory(SessionFactory factory) { this.factory = factory; } public E get(int id) { return super.get(id); } public void save(E entity) { super.save(entity); } public void delete(E entity) { super.delete(entity); } }

Y ahora la clase extendida se vería así:

@Repository @Transactional("manager1") // You''d probably still want the @Transactional for new methods public class Dao1 extends TransactionalDao<Entity1> { @Overrides @Autowired @Qualifier("factory1") public void setSessionFactory(SessionFactory factory) { super.setSessionFactory(factory); } }

De esta manera, solo tienes que hacer esto super envoltura solo una vez.