在实际项目中,尤其是复杂系统,往往需要连接多个数据源,实现多数据库读写,这时就需要配置多数据源连接,而Spring Boot整合MybatisPlus实现多数据源有两种方式:分包 和 AOP。习惯问题,这里讲的是分包方式实现,借用网上的一张图说明很清晰了:
本文在已经配置好mybatisPlus和druid的前提下增加为多数据源的,不清楚可以参考前面的文章
properties.xml中设置两个数据源,假设这里的数据库分别为mickey和tianji
spring.datasource.druid.mickey.jdbc-url=你的数据库地址
spring.datasource.druid.mickey.username=mickey
spring.datasource.druid.mickey.password=***
spring.datasource.druid.mickey.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.mickey.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.tianji.jdbc-url=你的数据库地址
spring.datasource.druid.tianji.username=tianji
spring.datasource.druid.tianji.password=***
spring.datasource.druid.tianji.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.tianji.type=com.alibaba.druid.pool.DruidDataSource
数据源1为默认数据源,需要使用注解 @Primary
@Configuration
@MapperScan(basePackages = "com.demo.mapper.mickey", sqlSessionTemplateRef = "mickeySqlSessionTemplate")
public class MickeyDsConfig {
@Primary
@Bean(name = "mickey")
@ConfigurationProperties(prefix = "spring.datasource.druid.mickey")
public DataSource mickeyDataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "mickeySqlSessionFactory")
public SqlSessionFactory mickeySqlSessionFactory(@Qualifier("mickey") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Primary
@Bean(name = "mickeyTransactionManager")
public DataSourceTransactionManager mickeyTransactionManager(@Qualifier("mickey") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Primary
@Bean(name = "mickeySqlSessionTemplate")
public SqlSessionTemplate mickeySqlSessionTemplate(@Qualifier("mickeySqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
@Configuration
@MapperScan(basePackages = "com.demo.mapper.tianji", sqlSessionTemplateRef = "tianjiSqlSessionTemplate")
public class TianjiDsConfig {
@Bean(name = "tianji")
@ConfigurationProperties(prefix = "spring.datasource.druid.tianji")
public DataSource tianjiDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "tianjiSqlSessionFactory")
public SqlSessionFactory tianjiSqlSessionFactory(@Qualifier("tianji") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "tianjiTransactionManager")
public DataSourceTransactionManager tianjiTransactionManager(@Qualifier("tianji") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "tianjiSqlSessionTemplate")
public SqlSessionTemplate tianjiSqlSessionTemplate(@Qualifier("tianjiSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
到这里,查询数据正常了,但是遇到了一个问题,发现分页查询无效了,不只是分页查询,此前配置的乐观锁插件,防止全表更新与删除全部都失效了,解决方法:需要在配置数据源时,重新将插件注入到数据源中。
将插件plugins汇总起来
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
@Bean(name = "plugins")
public Interceptor[] plugins() {
return new Interceptor[]{ optimisticLockerInnerInterceptor(),paginationInterceptor(), blockAttackInnerInterceptor() };
}
/** 乐观锁插件 */
@Bean(name = "optimisticLockerInnerInterceptor")
public MybatisPlusInterceptor optimisticLockerInnerInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
/** 分页插件 */
@Bean(name = "paginationInterceptor")
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
/* 单页分页条数限制 */
pageInterceptor.setMaxLimit(20L);
interceptor.addInnerInterceptor(pageInterceptor);
return interceptor;
}
/** 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除) */
@Bean(name = "configurationCustomizer")
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
/** 防止全表更新与删除 */
@Bean(name = "blockAttackInnerInterceptor")
public MybatisPlusInterceptor blockAttackInnerInterceptor() {
/**去除警告,目前暂时无影响,持续关注*/
disableWarning();
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
/*针对 update 和 delete 语句*/
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
/**
* 去除Warning
*/
private static void disableWarning() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe u = (Unsafe) theUnsafe.get(null);
Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger");
Field logger = cls.getDeclaredField("logger");
u.putObjectVolatile(cls, u.staticFieldOffset(logger), null);
} catch (Exception e) {
}
}
}
将SqlSessionFactoryBean改用MybatisSqlSessionFactoryBean,将plugins重新注入数据源配置中
@Autowired
@Qualifier("plugins")
private Interceptor[] plugins;
@Primary
@Bean(name = "mickeySqlSessionFactory")
public SqlSessionFactory mickeySqlSessionFactory(@Qualifier("mickey") DataSource dataSource) throws Exception {
// SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
/** 当使用myBatis-plus的时候需要使用 MybatisSqlSessionFactoryBean */
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
/**当使用多数据源时,mybatisPlus默认配置将会失效,需要单独将其注入数据源中 */
bean.setPlugins(plugins);
return bean.getObject();
}
完整的文件为
@Configuration
@MapperScan(basePackages = "com.demo.mapper.mickey", sqlSessionTemplateRef = "mickeySqlSessionTemplate")
public class MickeyDsConfig {
@Autowired
@Qualifier("plugins")
private Interceptor[] plugins;
@Primary
@Bean(name = "mickey")
@ConfigurationProperties(prefix = "spring.datasource.druid.mickey")
public DataSource mickeyDataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "mickeySqlSessionFactory")
public SqlSessionFactory mickeySqlSessionFactory(@Qualifier("mickey") DataSource dataSource) throws Exception {
// SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
/** 当使用myBatis-plus的时候需要使用 MybatisSqlSessionFactoryBean */
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
/**当使用多数据源时,mybatisPlus默认配置将会失效,需要单独将其注入数据源中 */
bean.setPlugins(plugins);
return bean.getObject();
}
@Primary
@Bean(name = "mickeyTransactionManager")
public DataSourceTransactionManager mickeyTransactionManager(@Qualifier("mickey") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Primary
@Bean(name = "mickeySqlSessionTemplate")
public SqlSessionTemplate mickeySqlSessionTemplate(@Qualifier("mickeySqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
总结: