我正在使用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)。任何帮助都会很棒。
答案 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。