spring boot 中 Mybatis plus 多数据源的配置方法
最近在学习spring boot,发现在jar包依赖方面做很少的工作量就可以了,对于数据库操作,我用的比较多的是mybatis plus,在中央仓库已经有mybatis-plus的插件了,对于单数据源来说直接使用就是了,但我自己的项目经常会有多数据源的情况,自己去试着写数据源的代码,核心的方法参考mp说明文档中多数据源的处理,使用动态数据源,根据需求去切换数据源
新建spring-boot项目
这一步大家去参考其它教程,很简单
定义数据源相关Model
动态数据源
继承了抽像的数据源,并实现了DataSource,归根结底还是数据就是了,在这里面进行扩展,实现determiniCurrentlookupKey,也就是获取当前需要使用数据源的key值,在父类方法中有一个map,用来保存key值与数据源的对应关系,而key值是与当前线程相关的,DbcontextHolder代码见下
-
package com.zhangshuo.common.dataSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * Created by Administrator on 2017/5/31 0031. */ publicclassDynamicDataSourceextendsAbstractRoutingDataSource{ /** * 取得当前使用哪个数据源 * * @return */ @Override protectedObject determineCurrentLookupKey(){ returnDbContextHolder.getDbType(); } }
定义DbContextHolder
里面包含静态方法,用来设置或获取线程相关的数据源别名
-
publicclassDbContextHolder{ privatestaticfinalThreadLocal<String> contextHolder =newThreadLocal<>(); /** * 设置数据源 * * @param dbTypeEnum */ publicstaticvoid setDbType(DBTypeEnum dbTypeEnum){ contextHolder.set(dbTypeEnum.getValue()); } /** * 取得当前数据源 * * @return */ publicstaticString getDbType(){ return contextHolder.get(); } /** * 清除上下文数据 */ publicstaticvoid clearDbType(){ contextHolder.remove(); } }
定义数据源枚举类
简化设置线程相关数据源名称的记忆压力;直接从所有的数据源的枚举中去选就可以了~
-
publicenumDBTypeEnum{ datasource1("datasource1"), datasource2("datasource2"); privateString value; DBTypeEnum(String value){ this.value = value; } publicString getValue(){ return value; } }
生成 dataource 对象及 mp需要的对象
resources/application.properties的配置
在这里定义的属性名要与DruidDataSource和 SqlSessionFactory中需要的属性相同,使用ConfigurationProperties注解来减少代码
-
datasource1: username: root password: 123456 filters: mergeStat,wall,logback initialSize: 5 maxActive: 50 minIdle: 5 maxWait: 6000 validationQuery: SELECT 'x' testOnBorrow: true testOnReturn: true testWhileIdle: true timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 removeAbandoned: true removeAbandonedTimeout: 1800 logAbandoned: true url: jdbc:mysql://192.168.168.118:3306/test?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&useSSL=false mybatis-plus1: # 数据源名称 datasource: datasource1 # mapper配置路径 mapperLocations: classpath:/mapper/test1/*.xml # mybatis配置路径 configLocation: classpath:/mybatis-config.xml # entity的包 typeAliasesPackage: com.zhangshuo/test1/entity # 全局配置 globalConfiguration: # id生成策略 0 自增 1 用户输入 idType: 0 # 灵据数类型 dbType: mysql # 字段是否为下划线格式 dbColumnUnderline: false datasource2: username: root password: 123456 filters: mergeStat,wall,logback initialSize: 5 maxActive: 50 minIdle: 5 maxWait: 6000 validationQuery: SELECT 'x' testOnBorrow: true testOnReturn: true testWhileIdle: true timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 removeAbandoned: true removeAbandonedTimeout: 1800 logAbandoned: true url: jdbc:mysql://192.168.168.118:3306/sms?useUnicode=true&characterEncoding=utf-8 mybatis-plus2: # 数据源名称 datasource: datasource2 # mapper配置路径 mapperLocations: classpath:/mapper/test2/*.xml # mybatis配置路径 configLocation: # entity的包 typeAliasesPackage: com.zhangshuo/test2/entity # 全局配置 globalConfiguration: # id生成策略 0 自增 1 用户输入 idType: 0 # 灵据数类型 dbType: mysql # 字段是否为下划线格式 dbColumnUnderline: false
生成相应对象
-
import com.alibaba.druid.pool.DruidDataSource; import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean; import com.zhangshuo.common.dataSource.DynamicDataSource; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; import java.util.Map; import java.sql.SQLException; import java.util.HashMap; /** * Created by Administrator on 2017/5/31 0031. */ @Configuration @MapperScan(value ={"com.zhangshuo.test1.mapper","com.zhangshuo.test2.mapper"}) publicclassDataSourceConfig{ @ConfigurationProperties(prefix ="datasource1") @Bean(name ="datasource1") // @Primary /** * 在方法上注解configurationProperties时,将会把属性注入到返回结果的bean中 */ publicDruidDataSource dataSource1()throwsSQLException{ returnnewDruidDataSource(); } @ConfigurationProperties(prefix ="datasource2") @Bean(name ="datasource2") /** * 在方法上注解configurationProperties时,将会把属性注入到返回结果的bean中 */ publicDruidDataSource dataSource2()throwsSQLException{ returnnewDruidDataSource(); } @Bean(name ="datasource") @Primary publicDynamicDataSource dynamicDataSource(@Qualifier(value ="datasource1")DataSource dataSource1,@Qualifier(value ="datasource2")DataSource dataSource2){ DynamicDataSource bean =newDynamicDataSource(); Map<Object,Object> targetDataSources =newHashMap<>(); targetDataSources.put("datasource1",dataSource1); targetDataSources.put("datasource2", dataSource2); bean.setTargetDataSources(targetDataSources); bean.setDefaultTargetDataSource(dataSource1); return bean; } @Bean(name ="sessionFactory1") @ConfigurationProperties(prefix ="mybatis-plus1") @ConfigurationPropertiesBinding() @Primary publicMybatisSqlSessionFactoryBean sqlSessionFactory1(@Qualifier(value ="datasource")DataSource dataSource){ MybatisSqlSessionFactoryBean bean =newMybatisSqlSessionFactoryBean(); bean.setDataSource(dataSource); return bean; } @Bean(name ="sessionFactory2") @ConfigurationProperties(prefix ="mybatis-plus2") @ConfigurationPropertiesBinding() publicMybatisSqlSessionFactoryBean sqlSessionFactory2(@Qualifier(value ="datasource")DataSource dataSource){ MybatisSqlSessionFactoryBean bean =newMybatisSqlSessionFactoryBean(); bean.setDataSource(dataSource); return bean; } }
设置AOP用来自动切换数据源
在这里说明下我的目录结构:
com.zhangshuo.test1.controller/service/mapper
com.zhangshuo.test2.controller/service/mapper
设置AOP
在dao层进行切换
-
import com.zhangshuo.common.dataSource.DBTypeEnum; import com.zhangshuo.common.dataSource.DbContextHolder; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * Created by Administrator on 2017/5/31 0031. * 以dao层进行切换 */ @Component @Aspect publicclassDataSourceInterceptor{ Logger logger =LoggerFactory.getLogger(DataSourceInterceptor.class); @Pointcut(value ="execution(public * com.zhangshuo.test1.mapper.**.*(..))") privatevoid datasource1ServicePointcut(){}; @Pointcut(value ="execution(public * com.zhangshuo.test2.mapper.**.*(..))") privatevoid datasource2ServicePointcut(){}; /** * 切换数据源1 */ @Before("datasource1ServicePointcut()") publicvoid dataSource1Interceptor(){ logger.debug("切换到数据源{}..............................","datasource1"); DbContextHolder.setDbType(DBTypeEnum.datasource1); } /** * 切换数据源2 */ @Before("datasource2ServicePointcut()") publicvoid dataSource2Interceptor(){ logger.debug("切换到数据源{}.......................","datasource2"); DbContextHolder.setDbType(DBTypeEnum.datasource2); } }
到这里就可以进行测试了;
顺带贴下mybatis-plus的分页插件,我是定义到了mybatis-config.xml中,也可以手动在sqlSessionfacotry中的setPlugins中()定义;
-
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-config.dtd"> <configuration> <settings> <setting name="cacheEnabled" value="false"/> <setting name="lazyLoadingEnabled" value="false"/> <setting name="aggressiveLazyLoading" value="true"/> <setting name="logImpl" value="slf4j"/> </settings> <plugins> <plugin interceptor="com.baomidou.mybatisplus.plugins.PaginationInterceptor"> <property name="dialectType" value="mysql" /> <property name="optimizeType" value="aliDruid" /> </plugin> </plugins> </configuration>