背景:
最近做了一个需求,是从 A 系统导入会员资料到 B 系统,
由于项目中做了数据源的切换,在 debug 的时候发现数据没回滚,这里简单记录一下,后续再补充。
代码
@Autowired
private DataSourceTransactionManager aTransactionManager;
@Autowired
private DataSourceTransactionManager bTransactionManager;
public void copyData() {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// A 系统开启事务
TransactionStatus statusA = aTransactionManager.getTransaction(def);
// 在A数据源中的操作
// ...
// B 系统开启事务
TransactionStatus statusB = bTransactionManager.getTransaction(def);
// 在B数据源中的操作
// ...
if (/*操作失败*/) {
aTransactionManager.rollback(statusA);
bTransactionManager.rollback(statusB);
} else {
aTransactionManager.commit(statusA);
bTransactionManager.commit(statusB);
}
}
顺便这里简单记录下多数据源在 SpringBoot 中的配置:
# yml 配置多数据源
server:
port: 9999
spring:
application:
name:data-synchronizer
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://xxx/db_name?serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false&failOverReadOnly=false&allowPublicKeyRetrieval=true
username: root
password: xxx
hikari:
pool-name: target-db
connection-timeout: 10000
validation-timeout: 10000
register-mbeans: true
data-source:
database:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: oracle.jdbc.OracleDriver
jdbc-url: jdbc:oracle:thin:@xxx:1521:orcl
username: xxx
password: xxx
hikari:
pool-name: source-db
connection-timeout: 10000
validation-timeout: 10000
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
typeAliasesPackage: com.xxxx.entity
configuration:
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
map-underscore-to-camel-case: false
cache-enabled: true
两个数据源配置类
/**
* 源数据库
* @author xxx
* @date 2023/11/23
*/
@Configuration
public class SourceDatabaseConfig {
@Bean(name = "sourceDataSource")
@ConfigurationProperties(prefix = "data-source.database")
public DataSource sourceDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public JdbcTemplate sourceJdbcTemplate() {
return new JdbcTemplate(sourceDataSource());
}
}
/**
* 目标数据库
* @author xxx
* @date 2023/11/23
*/
@Configuration
@MapperScan(basePackages = "mapper", sqlSessionTemplateRef = "sqlSessionTemplate")
public class TargetDatabaseConfig {
@Bean
@Primary
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
@Bean(name = "sqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
mybatisConfiguration.setMapUnderscoreToCamelCase(false);
mybatisConfiguration.setLogImpl(Slf4jImpl.class);
mybatisConfiguration.setCacheEnabled(true);
sqlSessionFactoryBean.setConfiguration(mybatisConfiguration);
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setBanner(false);
sqlSessionFactoryBean.setGlobalConfig(globalConfig);
return sqlSessionFactoryBean.getObject();
}
@Bean(name = "transactionManager")
@Primary
public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "sqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}