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.