matthew inger opened SPR-9661 and commented
By embedding the transaction manager name in the @Transactional anotations, using base dao classes is cumbersome. Example:
@Transactional
public class GenericDao
public GenericDao(Class<E> mappedClass, SessionFactory sessionFactory) {
this.mappedClass = mappedClass;
this.sessionFactory = sessionFactory;
}
@Transactional(readOnly=false)
public E getById(K key) {
return sessionFactory.getCurrentSession().get(mappedClass, key);
}
public E merge(E entity) {
return sessionFactory.getCurrentSession().merge(entity);
}
}
Now we have two subclasses, each of which will use different sessionfactory, and transaction manager (we don't need jta).
@Transactional("fooTxManager")
public class FooDao extends GenericDao
@Transactional("barTxManager")
public class FooDao extends GenericDao
The problem is that we'd have to override the getById() method otherwise that method will use the default transaction manager. Not a big deal with 1 method, but it is a big deal when there's a bunch of methods.
@Transactional("barTxManager")
public class FooDao extends GenericDao@Override
@Transactional("barTxManager")
public Foo getById(Long key) {
return super.getById(key);
}
...
}
I think a better approach would be to either:
a) Allow the transaction manager name, when left blank, to fallback to the annotation at the class level. b) Separate the transaction semantics from the manager name with a new annotation:
@TransactionManager("barTxManager")
Affects: 3.1.1
Comment From: spring-projects-issues
matthew inger commented
ps: in the mean time, i've extended the AnnotationTransactionAttributeSource to override the getTransactionAttribute method. In this subclass, i'm first calling super.getTransactionAttribute(), then i'm looking for the @Transactional on the target class (or any superclass or meta-annotation) and overriding the supplied (or default) transaction manager:
TransactionAttribute attribute = super.getTransactionAttribute(method, targetClass);
if (attribute != null) {
Transactional txManager = findTxManager(targetClass);
if (txManager != null) {
RuleBasedTransactionAttribute att = (RuleBasedTransactionAttribute) attribute;
att.setQualifier(txManager.value());
}
}
return attribute;
And to activate this, I'm using a bean factory post processor and replacing all of the definitions of AnnotationTransactionAttributeSource with my extension of it.
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
String[] beanNames = beanFactory.getBeanNamesForType(AnnotationTransactionAttributeSource.class);
for(String beanName : beanNames) {
BeanDefinition def = beanFactory.getBeanDefinition(beanName);
def.setBeanClassName(TxManagerAnnotationTransactionAttributeSource.class.getName());
}
}
Comment From: spring-projects-issues
matthew inger commented
PS: When i said this: Allow the transaction manager name, when left blank, to fallback to the annotation at the class level
I mean let the actual targetClass be allowed to determine the transaction manager, instead of forcing it to the class where the method is implemented.
Comment From: spring-projects-issues
Bulk closing outdated, unresolved issues. Please, reopen if still relevant.
Comment From: elab
I have exact the same problem when trying to reuse methods from the base DAO class with transaction manager of the concrete DAO class. How to achieve that?
The workaround by @mattinger from 2012 is unfortunately not working anymore due to multiple changes in the Spring code.
Related: #14011