【问题标题】:Multiple Transaction Managers in Spring Boot for different EntityManagersSpring Boot 中针对不同 EntityManager 的多个事务管理器
【发布时间】:2015-05-30 02:56:42
【问题描述】:

我需要从一个应用程序连接到两个不同的数据库。问题是我的 appEntityManager 没有与之关联的事务管理器,我不知道该怎么做。 @Primary adminEntityManager 可以毫无问题地使用 spring boot 提供的那个,如here 所述。

上面的配置几乎可以独立运行。要完成 图片需要为两者配置TransactionManagers EntityManagers 也是如此。默认情况下可以选择其中之一 如果将其标记为 @Primary,则在 Spring Boot 中使用 JpaTransactionManager。这 other 必须显式注入到新实例中。或者你 可能能够使用跨越两者的 JTA 事务管理器。

我已经用

注释了配置
@EnableTransactionManagement

这里是相关的豆子

@Bean
@ConfigurationProperties(prefix = "datasource.app")
public DataSource appDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean
@Primary
@ConfigurationProperties(prefix = "datasource.admin")
public DataSource adminDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean
public LocalContainerEntityManagerFactoryBean appEntityManagerFactory(
        final EntityManagerFactoryBuilder builder) {
    return builder
            .dataSource(appDataSource())
            .packages("au.com.mycompany.app.bomcommon.domain")
            .persistenceUnit("appPersistentUnit")
            .build();
}

@Bean
@Primary
public LocalContainerEntityManagerFactoryBean adminEntityManagerFactory(
        final EntityManagerFactoryBuilder builder) {
    return builder
            .dataSource(adminDataSource())
            .packages("au.com.mycompany.app.bombatch")
            .persistenceUnit("adminPersistentUnit")
            .build();
}

//I thought this would do it but I am getting an exception
//No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: appTransactionManager,transactionManager
@Bean
public JpaTransactionManager appTransactionManager(@Qualifier("appEntityManagerFactory") final EntityManagerFactory emf) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(emf);
    return transactionManager;
}

更新

我最终以不同的方式做这件事。 see here.

【问题讨论】:

  • 您应该考虑使用 JTA 事务管理器来跨越两个实体管理器。
  • 您使用的是哪个 Spring Boot 版本?您可能会受到此回归的影响:jira.spring.io/browse/SPR-12577 - 如果您未使用 1.2.2,请升级。
  • 我使用的是最新版本 1.2.2
  • @manish 我该怎么做?只包括 atomikos 依赖项?我需要做的就是让两个实体管理器使用同一个事务管理器吗?
  • This post 具有 Atomikos JTA 事务管理器的 XML 配置。您应该能够轻松地将其转换为 Java 配置。对于您的情况,您首先必须确保您当前的数据源在后台使用 XA 驱动程序。然后,将这两个包装在两个单独的 Atomikos 数据源中。接下来,创建两个单独的本地实体管理器,指向 Atomikos 数据源(不是您的原始数据源)。最后,声明一个 Atomikos 事务管理器。

标签: spring spring-boot


【解决方案1】:

请参阅以下更改。这个对我有用。创建了 3 个数据源、3 个会话工厂和 3 个事务管理器。在chainedTransaction 中添加了这些事务管理器,如下所示:

                    @Configuration
                    @EnableTransactionManagement
                    public class HibernateConfiguration implements TransactionManagementConfigurer {


                        @Bean("chainedTransactionManager")
                        public PlatformTransactionManager transactionManager(
                                @Qualifier("transactionManager1") final HibernateTransactionManager transactionManager1,
                                @Qualifier("transactionManager2") final HibernateTransactionManager transactionManager2,
                                @Qualifier("transactionManager3") final HibernateTransactionManager transactionManager3) {

                            return new ChainedTransactionManager(transactionManager1, transactionManager2, transactionManager3);
                        }

                        @Override
                        public PlatformTransactionManager annotationDrivenTransactionManager() {
                            // TODO Auto-generated method stub
                            return transactionManager(oneTransactionManager(), twoTransactionManager(), threeTransactionManager());
                        }


                @Bean(name = "oneDataSource", destroyMethod="")
                      public DataSource oneDataSource() throws IllegalArgumentException, NamingException, SQLException {
                            HikariConfig hkConfig = new HikariConfig();
                            System.out.println(env.getRequiredProperty("spring1-datasource.jdbcUrl"));
                            hkConfig.setJdbcUrl(env.getRequiredProperty("spring1-datasource.jdbcUrl"));
                            hkConfig.setUsername(env.getRequiredProperty("spring1-datasource.username"));
                            hkConfig.setPassword(env.getRequiredProperty("spring1-datasource.password"));
                            hkConfig.setDriverClassName(env.getRequiredProperty("spring1-datasource.driverClassName"));
                            return new HikariDataSource(hkConfig);
                        }

                @Bean(name="oneSessionFactory")
                @Qualifier("oneSessionFactory") 
               public LocalSessionFactoryBean oneSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
                LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
                sessionFactory.setDataSource(oneDataSource());
                  sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
                  Properties hibernateProperties = new Properties();
                  hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
                  hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
                  sessionFactory.setHibernateProperties(hibernateProperties);
                return sessionFactory;

              }



        @Bean(name="transactionManager1")
          public HibernateTransactionManager oneTransactionManager() {
              HibernateTransactionManager oneTransactionManager = new HibernateTransactionManager();
              try {
                oneTransactionManager.setSessionFactory(oneSessionFactory().getObject());
                } catch (IllegalArgumentException | NamingException | SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
              return oneTransactionManager 
          }





    @Bean(name = "twoDataSource", destroyMethod="")
          public DataSource twoDataSource() throws IllegalArgumentException, NamingException, SQLException {
                HikariConfig hkConfig = new HikariConfig();
                System.out.println(env.getRequiredProperty("spring2-datasource.jdbcUrl"));
                hkConfig.setJdbcUrl(env.getRequiredProperty("spring2-datasource.jdbcUrl"));
                hkConfig.setUsername(env.getRequiredProperty("spring2-datasource.username"));
                hkConfig.setPassword(env.getRequiredProperty("spring2-datasource.password"));
                hkConfig.setDriverClassName(env.getRequiredProperty("spring2-datasource.driverClassName"));
                return new HikariDataSource(hkConfig);
            }



@Bean(name="twoSessionFactory")
    @Qualifier("twoSessionFactory") 
   public LocalSessionFactoryBean twoSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(twoDataSource());
      sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
      Properties hibernateProperties = new Properties();
      hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
      hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
      sessionFactory.setHibernateProperties(hibernateProperties);
    return sessionFactory;

  }





  @Bean(name="transactionManager2")
  public HibernateTransactionManager twoTransactionManager() {
      HibernateTransactionManager twoTransactionManager = new HibernateTransactionManager();
      try {
        twoTransactionManager.setSessionFactory(twoSessionFactory().getObject());
        } catch (IllegalArgumentException | NamingException | SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
      return twoTransactionManager
  }


@Bean(name = "threeDataSource", destroyMethod="")
      public DataSource threeDataSource() throws IllegalArgumentException, NamingException, SQLException {
            HikariConfig hkConfig = new HikariConfig();
            System.out.println(env.getRequiredProperty("spring3-datasource.jdbcUrl"));
            hkConfig.setJdbcUrl(env.getRequiredProperty("spring3-datasource.jdbcUrl"));
            hkConfig.setUsername(env.getRequiredProperty("spring3-datasource.username"));
            hkConfig.setPassword(env.getRequiredProperty("spring3-datasource.password"));
            hkConfig.setDriverClassName(env.getRequiredProperty("spring3-datasource.driverClassName"));
            return new HikariDataSource(hkConfig);
        }


    @Bean(name="threeSessionFactory")
    @Qualifier("threeSessionFactory") 
   public LocalSessionFactoryBean threeSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(threeDataSource());
      sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
      Properties hibernateProperties = new Properties();
      hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
      hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
      sessionFactory.setHibernateProperties(hibernateProperties);
    return sessionFactory;

  }





  @Bean(name="transactionManager3")
  public HibernateTransactionManager threeTransactionManager() {
      HibernateTransactionManager threeTransactionManager = new HibernateTransactionManager();
      try {
        threeTransactionManager.setSessionFactory(threeSessionFactory().getObject());
        } catch (IllegalArgumentException | NamingException | SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
      return threeTransactionManager
  }

                           }

【讨论】:

    【解决方案2】:

    看看这是否有效:

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "datasource.admin")
    public DataSource adminDS() { ... }
    
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean adminEMF(...) { ... }
    
    @Bean
    @Primary
    public JpaTransactionManager adminTM(...) { ... }
    
    @Bean
    public LocalContainerEntityManagerFactoryBean appEMF(...) { ... }
    
    @Bean
    public JpaTransactionManager appTM(...) { ... }
    

    我对您的配置所做的唯一更改是为管理端显式声明事务管理器并将该事务管理器标记为默认值。

    【讨论】:

    • 我确实尝试过,但没有奏效。我继续收到有关拥有多个事务管理器的错误,即使它标记为@Primary。
    • 为我工作。请参阅 Github 上的 this sample application。所有单元测试均通过。
    • 我最终采用了不同的方式,但会接受这个答案,因为它似乎有效。 see here
    • 如果您也将您的解决方案添加为这篇文章的答案,这将对将来偶然发现这篇文章的用户大有裨益。根据您喜欢的解决方案,您可以选择适当的答案作为接受的答案。或者,您可以使用您所采取的方法在问题的底部添加一个小简介。
    猜你喜欢
    • 2017-05-29
    • 1970-01-01
    • 2016-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-07
    • 2015-04-24
    相关资源
    最近更新 更多