背景
一季度的时候,要搞数据迁移,大家基本都用datax迁移。但是我这边业务太复杂了,纯SQL不太能支持,就选择用代码程序迁移。因为旧的数据在不同的库,就产生了要从多个数据源读数据,然后写入到2个新的数据库。之前工程的配置都是只有一个库,我就开始踩坑了。
因为是两个同学一起开发的,另一个同学选择了mybatis的dynamic-datasource中间件,但是实践下来发现,无法做事务处理。然后就采用了我的方式,自己手动配置数据源。
数据源配置
主要依赖
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.18</version>
</dependency>
<!--mybatisPlus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.2</version>
</dependency>
<!--boot-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.22.RELEASE</version>
</parent>
配置
配置文件
我连了6个库,这里举例简化就写两个代表,一个mysql的,一个oracle
spring:
datasource:
ds01:
driverClassName: com.mysql.jdbc.Driver
username: ***
password: ***
url: jdbc:mysql://***:3306/ds01?useSSL=false&autoReconnect=true&autoReconnectForPools=true&characterEncoding=UTF-8&allowMultiQueries=true
type: com.alibaba.druid.pool.DruidDataSource
# 定义初始连接数
initial-size: 5
# 定义最大空闲
max-idle: 100
# 定义最小空闲
min-idle: 5
# 定义最大连接数
max-active: 100
# 定义最长等待时间
max-wait: 60000
validation-query: SELECT 1 FROM DUAL
test-on-borrow: true
test-on-return: true
test-while-idle: true
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
ds02:
username: ****
password: ****
url: jdbc:oracle:thin:@****:1521/ds02
type: com.alibaba.druid.pool.DruidDataSource
initial-size: 5
min-idle: 5
max-active: 100
max-wait: 60000
validation-query: SELECT 1 FROM DUAL
test-on-borrow: true
test-on-return: true
test-while-idle: true
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
配置类
每个数据源增加一个对应的配置类,由于都是相同的,只写一个示例
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.***.mapper.ds01", sqlSessionTemplateRef = "ds01SqlSessionTemplate")
public class DS01DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.ds01")
public DataSource ds01DataSource() {
return new DruidDataSource();
}
@Bean
public SqlSessionFactory ds01SqlSessionFactory(@Qualifier("ds01DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mybatis/mapper/ds01/*.xml"));
return bean.getObject();
}
@Bean
public DataSourceTransactionManager ds01TransactionManager(@Qualifier("ds01DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public SqlSessionTemplate ds01SqlSessionTemplate(@Qualifier("ds01SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
事务使用
在需要开启事务的方法上,加上@Transactional就好,只是要指定transactionManager
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, transactionManager = "ds01TransactionManager")
其他问题
BaseMapper封装的方法无法使用
【问题详细描述】提示未找到绑定的SQL,但是自定义的SQL可以正常使用
【解决】是因为有数据源的Config类,在配置文件中的配置不生效,所以需要手动配置。在设置SqlSessionFactory时,将SqlSessionFactoryBean替换为MybatisSqlSessionFactoryBean即可。
分页查询不生效
【问题详细描述】pageNum和pageSize设置的值未被使用,每次都是查全部数据
【解决】依然是配置问题。在设置SqlSessionFactory时,增加分页的配置
// 分页插件配置
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setLimit(-1);
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setPlugins(new Interceptor[]{paginationInterceptor});
开启SQL日志
【问题详细描述】一次SQL执行耗时较长,如果不开启日志,就无法了解执行情况,看起来就行程序卡住了,什么都没做
【解决1】依然是在设置SqlSessionFactory时,增加配置。但是这个配置是只在控制台打印
// 配置打印sql语句
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setLogImpl(StdOutImpl.class);
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setConfiguration(configuration);
【解决2】配置打印SQL到日志文件,其实只是配置下打印日志等级就好
logging:
level.*: INFO
path: ./logs
level:
com.***.mapper: debug
优化
针对上述SqlSessionFactory的配置问题,多个数据源通用,所以可以抽出来一个公共配置的方法。如下
public class MybatisPlusConfig {
public static SqlSessionFactory mybatisSqlSessionFactoryBean(DataSource dataSource, String resource) throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
//设置数据源
bean.setDataSource(dataSource);
// 分页插件配置
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setLimit(-1);
bean.setPlugins(new Interceptor[]{paginationInterceptor});
// 配置打印sql语句
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setLogImpl(StdOutImpl.class);
bean.setConfiguration(configuration);
// 配置xml文件路径
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(resource));
return bean.getObject();
}
}
参考
springboot + mybatis + druid + 多数据源
mybatis plus分页total=0、不计算总数的终极解决方案!!!
springboot+mybatis-plus 两种方式打印sql语句
spring boot多数据源mybatis-plus的baseMapper的里面的方法无法使用
解决MyBatis Sql Log插件不打印sql记录的问题