Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@Transactional with txManager name is cumbersome with base dao classes [SPR-9661] #14295

Closed
spring-projects-issues opened this issue Aug 1, 2012 · 4 comments
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) status: bulk-closed An outdated, unresolved issue that's closed in bulk as part of a cleaning process

Comments

@spring-projects-issues
Copy link
Collaborator

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<K extends Serializable,E> {
protected Class<E> mappedClass;
protected SessionFactory sessionFactory;

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<Long, Foo> {
...
}

@Transactional("barTxManager")
public class FooDao extends GenericDao<Long, Foo> {
...
}

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<Long, Foo> {
@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

@spring-projects-issues
Copy link
Collaborator Author

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());
    }
}

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues spring-projects-issues added status: waiting-for-triage An issue we've not yet triaged or decided on in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement and removed type: enhancement A general enhancement labels Jan 11, 2019
@rstoyanchev rstoyanchev added status: bulk-closed An outdated, unresolved issue that's closed in bulk as part of a cleaning process and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jan 11, 2019
@spring-projects-issues
Copy link
Collaborator Author

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.

@elab
Copy link

elab commented Jan 3, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) status: bulk-closed An outdated, unresolved issue that's closed in bulk as part of a cleaning process
Projects
None yet
Development

No branches or pull requests

3 participants