spring-boot-starter-jta-atomikos
记录开发中碰到的问题,后端项目需要配置两个不同的数据库,一开始本来用的是AOP进行切换数据源,但是会遇到一个方法用到两个不同数据源进行关联更新数据时,@Transactional会缓存当前事务,导致无法切换数据源,并且不能全部回滚。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
mysql:
datasource:
template:
url: jdbc:mysql://localhost:5432/template
username: simple
password: simple
driverClassName: com.mysql.cj.jdbc.Driver
minPoolSize: 3
maxPoolSize: 25
maxLifetime: 20000
mborrowConnectionTimeout: 30
loginTimeout: 30
maintenanceInterval: 60
maxIdleTime: 60
lyj:
url: jdbc:mysql://localhost:5432/lyj
username: simple
password: simple
driverClassName: com.mysql.cj.jdbc.Driver
minPoolSize: 3
maxPoolSize: 25
maxLifetime: 20000
mborrowConnectionTimeout: 30
loginTimeout: 30
maintenanceInterval: 60
maxIdleTime: 60
将配置转化成Java Bean
@ConfigurationProperties(prefix = "mysql.datasource.lyj")
@Component
public class LyjDBConfig {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String driverClassName;
private String testQuery;
}
@ConfigurationProperties(prefix = "mysql.datasource.template")
@Component
public class LyjDBConfig {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String driverClassName;
private String testQuery;
}
配置两个数据源
@Configuration
@MapperScan(basePackages = "com.dhy.remotesensing.mapper.template", sqlSessionTemplateRef = "postgresqlSessionTemplate")
public class TemplateMybatisConfig {
@Autowired
TemplateDBConfig templateDBConfig;
@Bean("templateDataSource")
public DataSource templateDataSource() throws SQLException {
DruidXADataSource druidXADataSource = new DruidXADataSource();
druidXADataSource.setUrl(templateDBConfig.getUrl());
druidXADataSource.setPassword(templateDBConfig.getPassword());
druidXADataSource.setUsername(templateDBConfig.getUsername());
druidXADataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setUniqueResourceName("templateDataSource");
xaDataSource.setMinPoolSize(templateDBConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(templateDBConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(templateDBConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(templateDBConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(templateDBConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(templateDBConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(templateDBConfig.getMaxIdleTime());
xaDataSource.setXaDataSource(druidXADataSource);
return xaDataSource;
}
@Bean(name = "templateSimpleSessionFactory")
public SqlSessionFactory templateSimpleSessionFactory(@Qualifier("templateDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resourceResolver.getResources("classpath:mapper/template/*.xml"));
bean.setTypeAliasesPackage("com.dhy.remotesensing.pojo.*");
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
bean.setConfiguration(configuration);
return bean.getObject();
}
@Bean(name = "postgresqlSessionTemplate")
public SqlSessionTemplate postgresqlSessionTemplate(
@Qualifier("templateSimpleSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
@Configuration
@MapperScan(basePackages = "com.dhy.remotesensing.mapper.lyj",sqlSessionTemplateRef = "lyjSessionTemplate")
public class LyjMybatisConfig {
@Autowired
LyjDBConfig lyjDBConfig;
@Bean("lyjDataSource")
public DataSource lyjDataSource() throws SQLException {
DruidXADataSource druidXADataSource = new DruidXADataSource();
druidXADataSource.setUrl(lyjDBConfig.getUrl());
druidXADataSource.setPassword(lyjDBConfig.getPassword());
druidXADataSource.setUsername(lyjDBConfig.getUsername());
druidXADataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setUniqueResourceName("lyjDataSource");
xaDataSource.setMinPoolSize(lyjDBConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(lyjDBConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(lyjDBConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(lyjDBConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(lyjDBConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(lyjDBConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(lyjDBConfig.getMaxIdleTime());
xaDataSource.setXaDataSource(druidXADataSource);
return xaDataSource;
}
@Bean(name = "lyjSessionFactory")
public SqlSessionFactory lyjSessionFactory(@Qualifier("lyjDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resourceResolver.getResources("classpath:mapper/lyj/*.xml"));
bean.setTypeAliasesPackage("com.dhy.remotesensing.pojo.*");
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
bean.setConfiguration(configuration);
return bean.getObject();
}
@Bean(name = "lyjSessionTemplate")
public SqlSessionTemplate lyjSessionTemplate(
@Qualifier("lyjSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
基本配置就是这样了,使用@Transactional 都会回滚了。