【问题标题】:Spring : Do I require to define separate TransactionManager for 2 data sources?Spring:我是否需要为 2 个数据源定义单独的 TransactionManager?
【发布时间】:2018-06-19 12:16:03
【问题描述】:

我正在开发一个 Spring-MVC 应用程序,其中我为不同类型的任务定义了 2 个数据源。目前,在从 XML 迁移到 Java 的过程中,我偶然发现需要添加一个新的 HibernateTransactionManager 对象以使 @Transactional 工作。对于 2 个不同的数据源,我有 2 个单独的 SessionFactory 实例。但是当我尝试使用辅助数据源创建另一个 HibernateTransactionManager 实例时,我得到一个非唯一异常。

对于我发布的配置,我是否需要一个辅助 HibernateTransactionManager 实例,或者 1 个就足够了?如果需要,我如何创建一个?谢谢。

错误日志:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: primary_tx,extended_tx
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:368)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:367)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:271)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springfram

WebConfig.java:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.ourapp.spring"})
@EnableTransactionManagement
@EnableCaching
public class WebConfig extends WebMvcConfigurerAdapter {


 @Bean(name="primary_tx")
    public HibernateTransactionManager getPrimaryTransactionManager() throws IOException {
        HibernateTransactionManager txName= new HibernateTransactionManager();
        txName.setSessionFactory(sessionFactory().getObject());
        return txName;
    }

    @Bean(name="extended_tx")
    public HibernateTransactionManager txName() throws IOException {
        HibernateTransactionManager txName= new HibernateTransactionManager();
        txName.setSessionFactory(getExtendedSessionFactory().getObject());
        return txName;
    }

    @Bean
    @Qualifier("sessionFactory_origin")
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(new DataSourceConfig().primaryDataSource());
        sessionFactory.setPackagesToScan("com.ourapp.spring");
        return sessionFactory;
    }

     @Bean
@Qualifier("sessionFactory_extended")
public LocalSessionFactoryBean getExtendedSessionFactory() {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(new DataSourceConfig_Extended().secondaryDataSource());
    sessionFactory.setPackagesToScan("com.ourapp.spring");
    return sessionFactory;
}
}

典型的服务层方法:

@Service
@Transactional("primary_tx")
public class ChatRoomMembersServiceImpl implements ChatRoomMembersService{


   private final ChatRoomMembersDAO chatRoomMembersDAO;

    @Autowired
    public ChatRoomMembersServiceImpl(ChatRoomMembersDAO chatRoomMembersDAO){
        this.chatRoomMembersDAO = chatRoomMembersDAO;
    }
}

典型的DAO层方法:

@Repository
@Transactional("primary_tx")
public class ChatRoomMembersDAOImpl implements ChatRoomMembersDAO{

    @Autowired
    @Qualifier(value = "sessionFactory_origin")
    private  SessionFactory sessionFactory;

    @Autowired
    @Qualifier(value = "sessionFactory_extended")
    private  SessionFactory sessionFactory_extended;

}

现在,每当需要时,我指的是扩展的 SessionFactory 实例。现在,我已经用secondary_tx 注释了需要扩展 sessionFactory 的 DAO 层方法,但它不起作用。谢谢你。 :-)

【问题讨论】:

    标签: java spring spring-mvc migration


    【解决方案1】:

    你的问题的答案

    我需要为 2 个数据源定义单独的 TransactionManager 吗?

    从 Java8 开始,您可以在一个方法上多次使用相同的注解(前提是注解标记为 @Repeatable)。实现此目的的另一种方法是提供一个自定义注释来处理其中一个数据源。

    您得到的例外是因为有两个符合条件的 bean 用于事务管理。为此,您需要一个限定符。

    代替:

    @Bean(name="primary_tx")
        public HibernateTransactionManager getPrimaryTransactionManager() throws IOException {
            HibernateTransactionManager txName= new HibernateTransactionManager();
            txName.setSessionFactory(sessionFactory().getObject());
            return txName;
        }
    

    使用

    @Bean @Qualifier("primary_tx")
    
        public HibernateTransactionManager getPrimaryTransactionManager() throws IOException {
            HibernateTransactionManager txName= new HibernateTransactionManager();
            txName.setSessionFactory(sessionFactory().getObject());
            return txName;
        }
    

    现在,假设您想让我的方法 m1 中的事务成为原子的。以下是你需要的

    @Transactional("primary_tx")
    public void m1(){
    }
    

    【讨论】:

    • 我在哪里添加这个?我只是在需要辅助事务的方法上使用@Transactional 注释。谢谢。
    • 你必须把它放在包含事务的方法上。它的工作方式非常简单。它使事务原子化,即要么全部成功执行,要么不提交任何内容
    • 我将其更改为使用限定符命名 HIbernateTransactionManager,但我得到了同样的错误。我还按照您的建议注释了所有方法。注意:我有 2 个返回 HibernateTransactionManager 的方法,每个方法都与 SessionFactory 的特定实例相关联。谢谢你。 :-)
    • @WeareBorg 消息很清楚expected single matching bean but found 2: primary_tx,extended_tx :) 此外,您需要将其从类级别中删除,所有您不希望所有方法都成为事务性
    • 我认为有些混乱。正如您所说,对于 2 个不同的数据源,我需要 2 个不同的 TransactionManager,这正是我现在拥有的方式。您能否更新您的答案以显示如何定义和调用 2 个事务管理器。谢谢你。我的非事务方法已经不在服务层类中了。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-25
    相关资源
    最近更新 更多