2014-01-10 135 views
3

我正在處理兩個在春天的交易,它參考了兩個entitymanagers,因此有兩個數據源,而使用@Transactional("transaction1")它工作正常,但@Transactional("transaction2")拋出一個錯誤,說沒有找到活動事務。以下是一段代碼:與兩個交易一起工作,一個似乎工作,但另一個不工作。爲什麼?

@Bean(name = "transaction1") 
     public PlatformTransactionManager transactionManager() { 
      JpaTransactionManager transactionManager = new JpaTransactionManager(); 
      transactionManager.setEntityManagerFactory(entityManagerFactoryBean2() 
        .getObject()); 
      return transactionManager; 
     } 

    @Bean(name = "transaction2") 
     public PlatformTransactionManager sermaTransactionManager() { 

      JpaTransactionManager transactionManager = new JpaTransactionManager(); 
      transactionManager 
        .setEntityManagerFactory(entityManagerFactoryBean1() 
          .getObject()); 

      return transactionManager; 
     } 

各自entitymanagers:

@Bean(name = "entitymanager1") 
     public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean1() { 

      LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); 
      entityManagerFactoryBean.setDataSource(dataSource1()); 
      entityManagerFactoryBean 
        .setPackagesToScan(new String[] { this.environment 
          .getProperty("db.packagesToScan") }); 
      entityManagerFactoryBean 
        .setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); 
      entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter()); 

      Map<String, Object> jpaProperties = new HashMap<String, Object>(); 
      jpaProperties.put("eclipselink.weaving", "false"); 
      jpaProperties.put("eclipselink.logging.level", "INFO"); 
      jpaProperties.put("eclipselink.logging.parameters", "true"); 
      entityManagerFactoryBean.setJpaPropertyMap(jpaProperties); 

      return entityManagerFactoryBean; 
     } 

    @Bean(name = "entitymanager2") 
     public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean2() { 

      LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); 
      entityManagerFactoryBean.setDataSource(dataSource2()); 
      entityManagerFactoryBean 
        .setPackagesToScan(new String[] { this.environment 
          .getProperty("db.packagesToScan") }); 
      entityManagerFactoryBean 
        .setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); 
      entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter()); 

      Map<String, Object> jpaProperties = new HashMap<String, Object>(); 
      jpaProperties.put("eclipselink.weaving", "false"); 
      jpaProperties.put("eclipselink.logging.parameters", "true"); 
      jpaProperties.put("eclipselink.logging.level", "INFO"); 
      entityManagerFactoryBean.setJpaPropertyMap(jpaProperties); 

      return entityManagerFactoryBean; 
     } 

相應數據源:

@Bean("datasource1") 
public DriverManagerDataSource dataSource1() { 

     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     dataSource      .setDriverClassName(this.environment.getProperty("db.driver")); 
     dataSource.setUrl(this.environment.getProperty("db.url")); 
     dataSource.setUsername(this.environment 
       .getProperty("db.username.abc")); 
     dataSource.setPassword(this.environment 
       .getProperty("db.password.abc")); 

     return dataSource; 
    } 
@Bean("datasource2") 
public DriverManagerDataSource dataSource2() { 

     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     dataSource 
       .setDriverClassName(this.environment.getProperty("db.driver")); 
     dataSource.setUrl(this.environment.getProperty("db.url")); 
     dataSource.setUsername(this.environment.getProperty("db.username")); 
     dataSource.setPassword(this.environment.getProperty("db.password")); 

     return dataSource; 
    } 

我genericDaoImpl具有以下到相應entitymanagers鏈接:

@PersistenceContext(unitName = "entitymanager1") 
    private EntityManager em1; 

    @PersistenceContext(unitName = "entitymanager2") 
    private EntityManager em2; 

當我做@Transactional(「transaction1」)它工作正常,但是當我做@Transactional(「transaction2」)它說沒有活動的交易。當我不提交交易的限定符時,錯誤說找到了兩個交易(transaction1,transaction2)。任何幫助都會很棒。

+0

我相信你需要在你的applicationContext.xml中聲明建議以傳播到事務 – esmoreno

+0

transactionManager1正在傳遞entityManagerFactoryBean2,這是正確的嗎? –

+0

您是否嘗試過配置張貼波紋管?它的工作 –

回答

1

沒有與配置的問題:

的問題是,當豆被初始化這樣的:

transactionManager.setEntityManagerFactory(entityManagerFactoryBean2().getObject()); 

entityManagerFactoryBean2()的通話將創建一個新的實體管理器工廠,那麼@Bean註釋會觸發創建另一個實體管理器工廠,使用相同的配置。

當你注入實體管理器工廠@Autowired在bean中,您注射用@Bean創建的實例,而不是實例傳遞到事務管理器。關於配置

一個警告:

在配置上面可以做交易在兩個不同的數據源,但這個配置做跨越數據庫的事務是不可能的。例如:

@Service 
public class PlanesService { 

    @PersistenceContext(unitName = "entityManagerFactory1") 
    private EntityManager em1; 

    @PersistenceContext(unitName = "entityManagerFactory2") 
    private EntityManager em2; 


    @Transactional("transactionManager1") 
    public Plane savePlanes() { 
     F14 f14 = new F14("F14","f14"); 
     F16 f16 = new F16("F16","f16"); 

     em1.persist(f14); 
     em2.persist(f16); 

     return f14; 
    } 
} 

此代碼將只能堅持F14,因爲有一個正在進行中的事務的唯一實體管理器EM1(由於@Transactional("transactionManager1"))。對em2.persist()的呼叫將被忽略(儘管em2仍然可以讀取)。

如果你想要做交易,包括兩個數據庫你需要一個JTA事務管理器。

工作配置的一個例子:

這能解決上述注入問題進行配置的例子:

@Configuration 
public class DataSourcesConfig { 

    @Bean(name = "datasource1") 
    public DriverManagerDataSource dataSource1() { 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     ... 
     return dataSource; 
    } 

    @Bean(name = "datasource2") 
    public DriverManagerDataSource dataSource2() { 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     ... 
     return dataSource; 
    } 
} 

@Configuration 
public class EntityManagerFactoriesConfiguration { 

    @Autowired 
    @Qualifier("datasource1") 
    private DataSource dataSource1; 

    @Autowired 
    @Qualifier("datasource2") 
    private DataSource dataSource2; 


    @Bean(name = "entityManagerFactory1") 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 

     LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); 
     entityManagerFactoryBean.setDataSource(dataSource1); 
     entityManagerFactoryBean.setPackagesToScan(new String[] { "your.package.here" }); 
     entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); 
     entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); 

     Map<String, Object> jpaProperties = new HashMap<String, Object>(); 
     ... 
     entityManagerFactoryBean.setJpaPropertyMap(jpaProperties); 

     return entityManagerFactoryBean; 
    } 

    @Bean(name = "entityManagerFactory2") 
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean2() { 

     LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); 
     entityManagerFactoryBean.setDataSource(dataSource2); 
     entityManagerFactoryBean.setPackagesToScan(new String[] { "your.package.here" }); 
     entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); 
     entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); 

     Map<String, Object> jpaProperties = new HashMap<String, Object>(); 

     entityManagerFactoryBean.setJpaPropertyMap(jpaProperties); 
     ... 
     return entityManagerFactoryBean; 
    } 
}  


@Configuration 
@EnableTransactionManagement 
public class TransactionManagersConfig { 

    @Autowired 
    @Qualifier("entityManagerFactory1") 
    EntityManagerFactory entityManagerFactory1; 

    @Autowired 
    @Qualifier("entityManagerFactory2") 
    EntityManagerFactory entityManagerFactory2; 

    @Autowired 
    @Qualifier("datasource1") 
    private DataSource dataSource1; 

    @Autowired 
    @Qualifier("datasource2") 
    private DataSource dataSource2; 

    @Bean(name = "transactionManager1") 
    public PlatformTransactionManager transactionManager1() { 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(entityManagerFactory1); 
     transactionManager.setDataSource(dataSource1); 
     return transactionManager; 
    } 

    @Bean(name = "transactionManager2") 
    public PlatformTransactionManager transactionManager2() { 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(entityManagerFactory2); 
     transactionManager.setDataSource(dataSource2); 
     return transactionManager; 
    } 
} 

通過幾個@Configuration類拆分配置和自動裝配它們,我們確保它始終使用相同的bean(單例)。

注意@EnableTransactionManagement註釋,它啓用@Transactional。

+1

它遲了一點回復@jhadesdev,但我最終使用了我的應用程序的路由數據源。謝謝你,你有一個很好的解釋,我學到了很多東西。 – Gurkha

相關問題