• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

Spring Boot 集成 Mybatis 实现双数据源

技术杂谈 勤劳的小蚂蚁 3个月前 (01-26) 67次浏览 已收录 0个评论 扫描二维码

这里用到了Spring Boot + Mybatis + DynamicDataSource配置动态双数据源,可以动态切换数据源实现数据库的读写分离。

添加依赖

加入Mybatis启动器,这里添加了Druid连接池、Oracle数据库驱动为例。
  1. <dependency>
  2.    <groupId>org.mybatis.spring.boot</groupId>
  3.    <artifactId>mybatis-spring-boot-starter</artifactId>
  4. </dependency>
  5. <dependency>
  6.    <groupId>com.alibaba</groupId>
  7.    <artifactId>druid</artifactId>
  8. </dependency>
  9. <dependency>
  10.    <groupId>com.oracle</groupId>
  11.    <artifactId>ojdbc6</artifactId>
  12. </dependency>

添加启动类

  1. @EnableMybatis
  2. @EnableTransactionManagement
  3. @SpringBootApplication(exclude ={DataSourceAutoConfiguration.class})
  4. publicclassApplication{
  5.    publicstaticvoid main(String[] args){
  6.        SpringApplication.run(ServiceApplication.class, args);
  7.    }
  8. }
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }): 这里用到了双数据源,需要排除数据源的自动配置,如果只有一个数据源用Spring Boot的自动配置就行。
@EnableTransactionManagement:开启事务支持。
@EnableMybatis:开启Mybatis功能
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(MybatisConfig.class)
  5. public@interfaceEnableMybatis{
  6. }

Mybatis配置类

  1. @Configuration
  2. @MapperScan(basePackages =DSConfig.BASE_PACKAGES)
  3. publicclassMybatisConfigimplementsDSConfig{
  4.    @Primary
  5.    @Bean
  6.    publicDynamicDataSource dynamicDataSource(@Qualifier(DB_MASTER)DataSource master,
  7.            @Qualifier(DB_SLAVE)DataSource slave){
  8.        Map<Object,Object> dsMap =newHashMap<>();
  9.        dsMap.put(DB_MASTER, master);
  10.        dsMap.put(DB_MASTER, slave);
  11.        DynamicDataSource dynamicDataSource =newDynamicDataSource();
  12.        dynamicDataSource.setDefaultTargetDataSource(master);
  13.        dynamicDataSource.setTargetDataSources(dsMap);
  14.        return dynamicDataSource;
  15.    }
  16.    @Bean
  17.    publicPlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource){
  18.        returnnewDataSourceTransactionManager(dynamicDataSource);
  19.    }
  20.    @Bean
  21.    publicSqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource)
  22.            throwsException{
  23.        SqlSessionFactoryBean sessionFactory =newSqlSessionFactoryBean();
  24.        sessionFactory.setDataSource(dynamicDataSource);
  25.        sessionFactory.setMapperLocations(
  26.                ((ResourcePatternResolver)newPathMatchingResourcePatternResolver())
  27.                        .getResources(DSConfig.MAPPER_LOCATIONS));
  28.        return sessionFactory.getObject();
  29.    }
  30. }
DSConfig常量类:
  1. publicinterfaceDSConfig{
  2.    String DS_PREFIX ="spring.datasource";
  3.    String DS_ACTIVE ="active";
  4.    String DB_MASTER ="db-master";
  5.    String DB_SLAVE ="db-slave";
  6.    String DRUID ="druid";
  7.    String DRUID_MONITOR_USERNAME ="spring.druid.username";
  8.    String DRUID_MONITOR_PASSWORD ="spring.druid.password";
  9.    String DRUID_MONITOR_URL ="/druid/*";
  10.    String DRUID_FILTER_EXCLUSIONS ="*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*";
  11.    String DRUID_FILTER_URL ="/*";
  12.    String BASE_PACKAGES ="com.example.**.mapper";
  13.    String MAPPER_LOCATIONS ="mapper/**/*.xml";
  14. }

连接池配置类

Druid连接池的自动配置类:
  1. @Configuration
  2. @Import({PropertiesConfig.class})
  3. @ConditionalOnClass(DruidDataSource.class)
  4. @ConditionalOnProperty(prefix =DSConfig.DS_PREFIX, value =DSConfig.DS_ACTIVE, havingValue =DSConfig.DRUID)
  5. publicclassDruidAutoConfigimplementsDSConfig{
  6.    privateLogger logger =LoggerUtils.getLogger(this);
  7.    @Bean(name = DB_MASTER, initMethod ="init", destroyMethod ="close")
  8.    publicDataSource dataSourceMaster(DruidMasterProperties masterProperties)throwsSQLException{
  9.        logger.debug("master properties: {}", masterProperties.toString());
  10.        DruidDataSource dds =newDruidDataSource();
  11.        dds.setDriverClassName(masterProperties.getDriverClassName());
  12.        dds.setUrl(masterProperties.getUrl());
  13.        dds.setUsername(masterProperties.getUsername());
  14.        dds.setPassword(masterProperties.getPassword());
  15.        dds.setInitialSize(masterProperties.getInitialSize());
  16.        dds.setMinIdle(masterProperties.getMinIdle());
  17.        dds.setMaxActive(masterProperties.getMaxActive());
  18.        dds.setMaxWait(masterProperties.getMaxWait());
  19.        dds.setTimeBetweenEvictionRunsMillis(masterProperties.getTimeBetweenEvictionRunsMillis());
  20.        dds.setMinEvictableIdleTimeMillis(masterProperties.getMinEvictableIdleTimeMillis());
  21.        dds.setValidationQuery(masterProperties.getValidationQuery());
  22.        dds.setTestOnBorrow(masterProperties.isTestOnBorrow());
  23.        dds.setTestWhileIdle(masterProperties.isTestWhileIdle());
  24.        dds.setTestOnReturn(masterProperties.isTestOnReturn());
  25.        dds.setPoolPreparedStatements(masterProperties.isPoolPreparedStatements());
  26.        dds.setMaxPoolPreparedStatementPerConnectionSize(
  27.                masterProperties.getMaxPoolPreparedStatementPerConnectionSize());
  28.        dds.setFilters(masterProperties.getFilters());
  29.        return dds;
  30.    }
  31.    @Bean(name = DB_SLAVE, initMethod ="init", destroyMethod ="close")
  32.    publicDataSource dataSourceSlave(DruidSlaveProperties slaveProperties)throwsSQLException{
  33.        logger.debug("slave properties: {}", slaveProperties.toString());
  34.        DruidDataSource dds =newDruidDataSource();
  35.        dds.setDriverClassName(slaveProperties.getDriverClassName());
  36.        dds.setUrl(slaveProperties.getUrl());
  37.        dds.setUsername(slaveProperties.getUsername());
  38.        dds.setPassword(slaveProperties.getPassword());
  39.        dds.setInitialSize(slaveProperties.getInitialSize());
  40.        dds.setMinIdle(slaveProperties.getMinIdle());
  41.        dds.setMaxActive(slaveProperties.getMaxActive());
  42.        dds.setMaxWait(slaveProperties.getMaxWait());
  43.        dds.setTimeBetweenEvictionRunsMillis(slaveProperties.getTimeBetweenEvictionRunsMillis());
  44.        dds.setMinEvictableIdleTimeMillis(slaveProperties.getMinEvictableIdleTimeMillis());
  45.        dds.setValidationQuery(slaveProperties.getValidationQuery());
  46.        dds.setTestOnBorrow(slaveProperties.isTestOnBorrow());
  47.        dds.setTestWhileIdle(slaveProperties.isTestWhileIdle());
  48.        dds.setTestOnReturn(slaveProperties.isTestOnReturn());
  49.        dds.setPoolPreparedStatements(slaveProperties.isPoolPreparedStatements());
  50.        dds.setMaxPoolPreparedStatementPerConnectionSize(
  51.                slaveProperties.getMaxPoolPreparedStatementPerConnectionSize());
  52.        dds.setFilters(slaveProperties.getFilters());
  53.        return dds;
  54.    }
  55.    @Bean
  56.    publicServletRegistrationBean druidServletRegistrationBean(EnvConfig env){
  57.        String username = env.getStringValue(DSConfig.DRUID_MONITOR_USERNAME);
  58.        String password = env.getStringValue(DSConfig.DRUID_MONITOR_PASSWORD);
  59.        returnnewServletRegistrationBean(newDruidStatViewServlet(username, password),
  60.                DSConfig.DRUID_MONITOR_URL);
  61.    }
  62.    @Bean
  63.    publicFilterRegistrationBean druidFilterRegistrationBean(){
  64.        WebStatFilter wsf =newWebStatFilter();
  65.        FilterRegistrationBean filterRegistrationBean =newFilterRegistrationBean();
  66.        filterRegistrationBean.setFilter(wsf);
  67.        filterRegistrationBean.setUrlPatterns(Arrays.asList(DSConfig.DRUID_FILTER_URL));
  68.        filterRegistrationBean.setInitParameters(
  69.                Collections.singletonMap("exclusions",DSConfig.DRUID_FILTER_EXCLUSIONS));
  70.        return filterRegistrationBean;
  71.    }
  72. }
根据类路径下有DruidDataSource这个类即有Druid这个jar包和配置文件中spring.datasource.active=druid才开启对Druid连接池的自动配置。
导入的配置文件:
  1. @Configuration
  2. @ComponentScan(basePackages ="com.example.common.config.properties")
  3. publicclassPropertiesConfig{
  4. }
DruidMasterProperties、DruidSlaveProperties属性文件读取的配置省略。
连接池监控配置类:
  1. publicclassDruidStatViewServletextendsStatViewServlet{
  2.    privatestaticfinallong serialVersionUID =1L;
  3.    privateString username;
  4.    privateString password;
  5.    @Override
  6.    publicString getInitParameter(String name){
  7.        if("loginUsername".equals(name)){
  8.            return username;
  9.        }
  10.        if("loginPassword".equals(name)){
  11.            return password;
  12.        }
  13.        returnsuper.getInitParameter(name);
  14.    }
  15.    publicDruidStatViewServlet(String username,String password){
  16.        super();
  17.        this.username = username;
  18.        this.password = password;
  19.    }
  20.    publicString getUsername(){
  21.        return username;
  22.    }
  23.    publicString getPassword(){
  24.        return password;
  25.    }
  26. }
在META-INF/spring.factories中加入Druid自动配置映射:
  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=
  2. com.example.common.config.ds.DruidAutoConfig

切换数据源
切换数据源注解:
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public@interface DS {
  5.    String value()defaultDSConfig.DB_MASTER;
  6. }
动态数据源类:
  1. publicclassDynamicDataSourceextendsAbstractRoutingDataSource{
  2.    privatefinalLogger logger =LoggerUtils.getLogger(this);
  3.    @Override
  4.    protectedObject determineCurrentLookupKey(){
  5.        logger.debug("当前数据源为{}",DataSourceContextHolder.getDS());
  6.        returnDataSourceContextHolder.getDS();
  7.    }
  8. }
动态数据源AOP实现类:
  1. @Aspect
  2. @Component
  3. publicclassDynamicDataSourceAspect{
  4.    @Before("@annotation(DS)")
  5.    publicvoid beforeSwitchDS(JoinPoint point){
  6.        Class<?> className = point.getTarget().getClass();
  7.        String methodName = point.getSignature().getName();
  8.        Class<?>[] argClass =((MethodSignature) point.getSignature()).getParameterTypes();
  9.        String dataSource =DataSourceContextHolder.DEFAULT_DS;
  10.        try{
  11.            Method method = className.getMethod(methodName, argClass);
  12.            if(method.isAnnotationPresent(DS.class)){
  13.                DS annotation = method.getAnnotation(DS.class);
  14.                dataSource = annotation.value();
  15.            }
  16.        }catch(Exception e){
  17.            e.printStackTrace();
  18.        }
  19.        DataSourceContextHolder.setDS(dataSource);
  20.    }
  21.    @After("@annotation(DS)")
  22.    publicvoid afterSwitchDS(JoinPoint point){
  23.        DataSourceContextHolder.clearDS();
  24.    }
  25. }
绑定当前线程数据源类:
  1. publicclassDataSourceContextHolder{
  2.    publicstaticfinalString DEFAULT_DS =DSConfig.DB_MASTER;
  3.    privatestaticfinalThreadLocal<String> DS_HOLDER =newThreadLocal<>();
  4.    publicstaticvoid setDS(String dbType){
  5.        DS_HOLDER.set(dbType);
  6.    }
  7.    publicstaticString getDS(){
  8.        return(DS_HOLDER.get());
  9.    }
  10.    publicstaticvoid clearDS(){
  11.        DS_HOLDER.remove();
  12.    }
  13. }


丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:Spring Boot 集成 Mybatis 实现双数据源
喜欢 (0)
[247507792@qq.com]
分享 (0)
勤劳的小蚂蚁
关于作者:
温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

您必须 登录 才能发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00