简体   繁体   English

Spring @交易和继承

[英]Spring @Transactional and inheritance

I do have a generics-based DAO class, which is base for all other DAO classes in my project and contains common functionality: 我确实有一个基于泛型的DAO类,该类是我项目中所有其他DAO类的基础,并且包含通用功能:

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: 现在,我想创建几个在不同数据库上运行的DAO:

@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. 但是问题是,子类的@Transactional并未覆盖Dao所有公共方法,因此不会进行任何事务管理。 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 : 我能想到的唯一选择是重写父类方法,因此它们是在继承的类中定义的,因此@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... 但是然后我将需要在每个 DAO类中执行此操作,并且代码到处都是相同的...

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. 如果您不介意super类也将是@Transactional ,则应将注释放在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: 如果您确实介意的话,我建议创建一个扩展类TransactionalDao ,该类将扩展主DAO并为@Transactional而所有应为@Transactional的DAO也将对其进行扩展:

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. 这样,您只需要做一次super包装即可。

Have you tried putting @Transaction on parent DAO class's methods? 您是否尝试过将@Transaction放在父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) {
        // ...
    }
}

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. 这样,当您在DAO1上调用save时,它将从子类中选择类级别的@Transaction(将指定要使用的TX管理器),然后从父级的save方法中选择方法级别的@Transactional。

Instead of adding @Transactional annotation everywhere, you should use AOP based Transaction Management like - 与其在所有地方添加@Transactional注释, @Transactional使用基于AOP的事务管理 -

<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>

It's good practice to use transaction on service layer. 在服务层上使用事务是一个好习惯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM