I do have a generics-based DAO class, which is base for all other DAO classes in my project and contains common functionality:
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) {
        // ...
    }
}
In my project I am using multiple datasources, pointing to different databases, therefore, I do have multiple session and transaction managers:
<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>
Now I want to create couple of DAOs, operating on different databases:
@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);
    }
}
but the problem is, that all public methods from Dao aren't covered by @Transactional from a child classes, so no transaction management occurs. The only option what I can think of is to override the parent class methods, so they are defined in inherited classes and therefore are taken care by @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);
    }
}
But then I would need to do this in every DAO class, and code would be everywhere the same...
Is there a better way how to share common functionality across all classes and still have all benefits of declarative transaction management?
In case you don't mind the super class would be @Transactional as well, you should put the annotation on the super DAO. In case you do mind, I suggest creating one extending class TransactionalDao that will extend the main DAO and be @Transactional and all the DAOs that should be @Transactional as well will extend it:
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);
    }
}
And now the extending class would look like that:
@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);
    }   
}
This way you only have to do this super wrapping thing only once.
Have you tried putting @Transaction on parent DAO class's methods?
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) {
        // ...
    }
}
That way when you call save on DAO1, it will pick up class-level @Transaction from the sub class (which will specify which TX manager to use) and then pick up method-level @Transactional from the parent's save method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With