大家项目都喜欢用Mybatis进行集成到springboot中,默认是单数据源的,那如果需要多数据源的时候,需要如何进行操作呢?
主要有几个方面:
(1)数据源的配置
(2)Mybatis插件配置
(3)事务和Mapper扫描配置
其实集成的过程中还是有一些坑的,让我们来细说一下。
配置文件如下,数据库和密码可自行修改
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
wxwork:
minimum-idle: 10
idle-timeout: 18000
maximum-pool-size: 1000
auto-commit: true
pool-name: HikariCP-Pool
max-lifetime: 1800000
connection-timeout: 300000
connection-test-query: SELECT 1
jdbc-url: jdbc:mysql://xxxA/dba?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: xx
password: xx
driver-class-name: com.mysql.cj.jdbc.Driver
wxbill:
jdbc-url: jdbc:mysql://xx/dbB?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: xx
password: xx
driver-class-name: com.mysql.cj.jdbc.Driver
minimum-idle: 10
idle-timeout: 18000
maximum-pool-size: 1000
auto-commit: true
pool-name: HikariCP-Pool-Bill
max-lifetime: 1800000
connection-timeout: 300000
connection-test-query: SELECT 1
现在要做的是配置2个数据源,这里也可以多个的,就看自身项目需要
里面的包扫描路径,需要根据自身的项目进行修改
@Configuration
@ConditionalOnProperty(prefix = "spring.datasource.xxA", name = "jdbc-url")
@EnableConfigurationProperties({MybatisProperties.class, PageHelperProperties.class})
@MapperScan(
basePackages = {"com.xxx.persist.mapper", "com.xxx.mapper"},
sqlSessionTemplateRef = "wxBillSqlSessionTemplate")
public class WxBillMybatisAutoConfiguration {
@Bean
@ConfigurationProperties("spring.datasource.xxxA")
public HikariDataSource wxBillDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean
public SqlSessionFactory wxBillSessionFactory(MybatisProperties mybatisProperties)
throws Exception {
return MybatisUtil.buildSessionFactory(
wxBillDataSource(), mybatisProperties, "classpath*:xxA.mapper/*.xml");
}
@Bean
public DataSourceTransactionManager wxBillTransactionManager() {
return new DataSourceTransactionManager(wxBillDataSource());
}
@Bean
public SqlSessionTemplate wxBillSqlSessionTemplate(MybatisProperties mybatisProperties)
throws Exception {
return new SqlSessionTemplate(wxBillSessionFactory(mybatisProperties));
}
}
配置数据库B的数据源
@Configuration
@ConditionalOnProperty(prefix = "spring.datasource.xxB", name = "jdbc-url")
@EnableConfigurationProperties(MybatisProperties.class)
@MapperScan(
basePackages = {"com.xx.mapper", "com.xx.mapper"},
sqlSessionTemplateRef = "wxWorkSqlSessionTemplate")
public class WxWorkMybatisAutoConfiguration {
@Bean
@Primary
@ConfigurationProperties("spring.datasource.xxB")
public HikariDataSource wxWorkDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean
@Primary
public SqlSessionFactory wxWorkSessionFactory(MybatisProperties mybatisProperties)
throws Exception {
return MybatisUtil.buildSessionFactory(
wxWorkDataSource(), mybatisProperties, "classpath*:mapper/*.xml");
}
@Bean
@Primary
public DataSourceTransactionManager wxWorkTransactionManager() {
return new DataSourceTransactionManager(wxWorkDataSource());
}
@Bean
@Primary
public SqlSessionTemplate wxWorkSqlSessionTemplate(MybatisProperties mybatisProperties)
throws Exception {
return new SqlSessionTemplate(wxWorkSessionFactory(mybatisProperties));
}
}
这么简单就完成了两个数据源的配置,里面有个很重要的方法,MybatisUtil,这里也是解决坑的地方
public class MybatisUtil {
public static SqlSessionFactory buildSessionFactory(
DataSource dataSource, MybatisProperties mybatisProperties, String mapLocation)
throws Exception {
// 这里需要复制属性
MybatisProperties localProperties =
BeanMapper.mapper(mybatisProperties, MybatisProperties.class);
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setVfs(SpringBootVFS.class);
bean.setDataSource(dataSource);
if (StringUtils.hasText(mapLocation)) {
localProperties.setMapperLocations(mapLocation.split(","));
}
if (!ObjectUtils.isEmpty(localProperties.resolveMapperLocations())) {
bean.setMapperLocations(localProperties.resolveMapperLocations());
}
if (localProperties.getConfigurationProperties() != null) {
bean.setConfigurationProperties(localProperties.getConfigurationProperties());
}
Configuration configuration =
BeanMapper.mapper(localProperties.getConfiguration(), Configuration.class);
bean.setConfiguration(configuration);
return bean.getObject();
}
}
这里查看源码会发现,Configuration这个对象,会跟MapperRegistry有关联,所以这里一定要重新生成一个对象,不然会发现查库时查到另外一个数据库上,大坑啊。
很多项目都会集成pageHelper插件,如果按照上面去运行,会发现插件并没有生效,因为都没有进行插件注册
@AllArgsConstructor
@Configuration
@EnableConfigurationProperties({PageHelperProperties.class})
public class PageHelperPluginAutoConfiguration {
private final List<SqlSessionFactory> sqlSessionFactoryList;
private final PageHelperProperties pageHelperProperties;
@PostConstruct
public void addPageInterceptor() {
PageInterceptor interceptor = new PageInterceptor();
Properties properties = new Properties();
properties.putAll(pageHelperProperties.getProperties());
interceptor.setProperties(properties);
for (SqlSessionFactory sqlSessionFactory : this.sqlSessionFactoryList) {
org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
if (!this.containsInterceptor(configuration, interceptor)) {
configuration.addInterceptor(interceptor);
}
}
}
private boolean containsInterceptor(
org.apache.ibatis.session.Configuration configuration, Interceptor interceptor) {
try {
return configuration.getInterceptors().contains(interceptor);
} catch (Exception ex) {
return false;
}
}
}
插件注册逻辑也很简单,就是找到配置的多个sessionFactory,然后把插件写入进去。
最后,肯定是要避开springboot自动配置的数据源,不然启动的时候会报错的
避开方法很简单
@SpringBootApplication(
scanBasePackages = "com.xxxx",
exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class,
})
到此为止,所有的多数据源和扫描配置都已经完成
需要注意的就是Mapper和Xml各种一定要分包和分文件夹,避免重复扫描。