使用两个交易,一个似乎工作,但另一个没有。为什么?

时间:2014-01-10 18:19:25

标签: java spring jpa jdbc entity

我正在使用spring上的两个事务,它引用了两个实体管理器,因此引用了两个数据源,而使用@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;
        }
各个实体经理:

    @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具有以下链接各个实体管理器:

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

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

当我执行@Transactional(“transaction1”)时,它工作正常,但是当我执行@Transactional(“transaction2”)时,它表示没有活动的事务。当我没有提到交易的限定符时,错误说找到了两个交易(transaction1,transaction2)。任何帮助都会很棒。

1 个答案:

答案 0 :(得分:1)

配置存在问题:

问题是当bean初始化时如下:

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

entityManagerFactoryBean2()的调用将创建一个新的实体管理器工厂,然后@Bean注释将触发创建另一个实体管理器工厂,具有相同的配置。

当您在bean中注入具有@Autowired的实体管理器工厂时,您将注入使用@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。