springboot+mybaties+druid+多数据源封装

mybaties-plus 代码生成器

导入依赖

<!--不需要添加 Mybatis及Mybatis-Spring依赖,Mybatis-Plus会自动维护-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!--生成文件所需模板引擎-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
package com.faraway.yy_commons.mybaties;

import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.DbType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import lombok.extern.slf4j.Slf4j;

/**
 *
 * 代码生成器
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/19 下午4:06
 */
@Slf4j
public class MpGenerator {

    public static void main(String[] args) {
        AutoGenerator autoGenerator = new AutoGenerator();

        // 选择模板引擎
        autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setAuthor("yuanyao@wistronits.com");
        gc.setOutputDir("/Users/yaoyuan/Desktop/itom_FH/yy_commons/src/main/java");
        gc.setFileOverride(false); // 是否覆盖同名文件
        gc.setActiveRecord(true);
        gc.setEnableCache(false); // 二级缓存
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(false);

        /* 自定义文件命名,注意 %s 会自动填充表实体属性! */
        // gc.setMapperName("%sDao");
        // gc.setXmlName("%sDao");
        // gc.setServiceName("MP%sService");
        // gc.setServiceImplName("%sServiceDiy");
        // gc.setControllerName("%sAction");

        autoGenerator.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setTypeConvert(new MySqlTypeConvert() {

            // 自定义数据库表字段类型转换【可选】
            @Override
            public DbColumnType processTypeConvert(String fieldType) {
                System.out.println("转换类型:" + fieldType);
                // 注意!!processTypeConvert 存在默认类型转换,如果不是你要的效果请自定义返回、非如下直接返回。
                return super.processTypeConvert(fieldType);
            }

        });

        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("yaoyuan12345");
        dsc.setUrl("jdbc:mysql://localhost:3306/yy_commons?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false");
        autoGenerator.setDataSource(dsc);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        // strategy.setCapitalMode(true);// 全局大写命名 ORACLE 注意
//        strategy.setTablePrefix(new String[] { "test_" });// 此处可以修改为您的表前缀
        strategy.setNaming(NamingStrategy.nochange);// 表名生成策略
        strategy.setInclude(new String[] { "user" }); // 需要生成的表
        // strategy.setExclude(new String[]{"test"}); // 排除生成的表
        // 自定义实体父类
        // strategy.setSuperEntityClass("com.baomidou.demo.TestEntity");
        // 自定义实体,公共字段
        // strategy.setSuperEntityColumns(new String[] { "test_id", "age" });
        // 自定义 mapper 父类
        // strategy.setSuperMapperClass("com.baomidou.demo.TestMapper");
        // 自定义 service 父类
        // strategy.setSuperServiceClass("com.baomidou.demo.TestService");
        // 自定义 service 实现类父类
        // strategy.setSuperServiceImplClass("com.baomidou.demo.TestServiceImpl");
        // 自定义 controller 父类
        // strategy.setSuperControllerClass("com.baomidou.demo.TestController");
        // 【实体】是否生成字段常量(默认 false)
        // public static final String ID = "test_id";
        // strategy.setEntityColumnConstant(true);
        // 【实体】是否为构建者模型(默认 false)
        // public User setName(String name) {this.name = name; return this;}
        // strategy.setEntityBuilderModel(true);
        autoGenerator.setStrategy(strategy);


        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.faraway.yy_commons.mybaties.bean");
//        pc.setModuleName("test");
        autoGenerator.setPackageInfo(pc);

        // 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】
//        InjectionConfig cfg = new InjectionConfig() {
//            @Override
//            public void initMap() {
//                Map<String, Object> map = new HashMap<String, Object>();
//                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
//                this.setMap(map);
//            }
//        };
//
//        // 自定义 xxList.jsp 生成
//        List<FileOutConfig> focList = new ArrayList<>();
//        focList.add(new FileOutConfig("/template/list.jsp.vm") {
//            @Override
//            public String outputFile(TableInfo tableInfo) {
//                // 自定义输入文件名称
//                return "D://my_" + tableInfo.getEntityName() + ".jsp";
//            }
//        });
//        cfg.setFileOutConfigList(focList);
//        mpg.setCfg(cfg);
//
//        // 调整 xml 生成目录演示
//        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
//            @Override
//            public String outputFile(TableInfo tableInfo) {
//                return "/develop/code/xml/" + tableInfo.getEntityName() + ".xml";
//            }
//        });
//        cfg.setFileOutConfigList(focList);
//        mpg.setCfg(cfg);
//
//        // 关闭默认 xml 生成,调整生成 至 根目录
//        TemplateConfig tc = new TemplateConfig();
//        tc.setXml(null);
//        mpg.setTemplate(tc);

        // 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改,
        // 放置自己项目的 src/main/resources/templates 目录下, 默认名称一下可以不配置,也可以自定义模板名称
        // TemplateConfig tc = new TemplateConfig();
        // tc.setController("...");
        // tc.setEntity("...");
        // tc.setMapper("...");
        // tc.setXml("...");
        // tc.setService("...");
        // tc.setServiceImpl("...");
        // 如上任何一个模块如果设置 空 OR Null 将不生成该模块。
        // mpg.setTemplate(tc);

        // 执行生成
        autoGenerator.execute();

        // 打印注入设置【可无】
//        System.err.println(mpg.getCfg().getMap().get("abc"));


    }
}

注意指定的包名即可

生成的mapper要用注入spring 开启mapper扫描

@MapperScan("com.faraway.yy_commons.mybaties.bean.mapper")

测试

@RestController
@RequestMapping("/user")
public class UserController {


    @Autowired
    IUserService userService;

    @GetMapping("/show")
    private String testUser() {


        Page<User> userPage = userService.selectPage(new Page<>(1, 10));
        String s = JSONObject.toJSONString(userPage);
        return s;
    }
}

至此mybaties-plus 完成

我使用的是mysql8.0.11 所以url路径和mysql5.6版本有出入

使用druid连接池

druid介绍:

Druid是阿里开源的一个JDBC应用组件, 其包括三部分:

DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系。 DruidDataSource 高效可管理的数据库连接池。 SQLParser SQL语法分析 通过Druid连接池中间件, 我们可以实现:

可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。 替换传统的DBCP和C3P0连接池中间件。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。 SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter-Chain机制,很方便编写JDBC层的扩展插件。

关于Druid的更多详细信息可以参考Druid官方文档 link

导入依赖:

<!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>

druid-spring-boot-starter对druid配置文件做了一些封装

配置文件

#数据源
spring:
  datasource:
    name: druidDataSource
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://${dbIp}:${dbPort}/${dbName}?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: ${dbUser}
      password: ${dbPwd}

#      配置监控统计拦截的filter , 去掉后监控sql无法统计wall用于防火墙
      filters: stat,wall,log4j,config

#      最大连接数
      max-active: 100

#      初始化大小
      initial-size: 1

#      获取连接等待超时时间
      max-wait: 60000

#      最小连接数
      min-idle: 1

#      间隔多久检测一次 检测需要关闭的空闲连接 单位毫秒
      time-between-eviction-runs-millis: 60000
#      一个连接最小生存时间
      min-evictable-idle-time-millis: 300000
      validation-query: select 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-open-prepared-statements: 50
      max-pool-prepared-statement-per-connection-size: 20
      
      

Druid提供以下几种Filter信息:

default    com.alibaba.druid.filter.stat.StatFilter

stat   com.alibaba.druid.filter.stat.StatFilter

mergeStat   com.alibaba.druid.filter.stat.MergeStatFilter

encoding   com.alibaba.druid.filter.encoding.EncodingConvertFilter

log4j   com.alibaba.druid.filter.logging.Log4jFilter

log4j2   com.alibaba.druid.filter.logging.Log4j2Filter

slf4j   com.alibaba.druid.filter.logging.Slf4jLogFilter

commonlogging   com.alibaba.druid.filter.logging.CommonsLogFilter

wall   com.alibaba.druid.wall.WallFilter

druid配置信息

通过Druid-Spring-Boot-Starter可以自动完成相关的配置, 而无须自定义配置文件, 具体参考

在此, 主要通过定制的配置文件对Druid进行自定义属性配置,项目中无需加入

配置文件如下:

package com.faraway.yy_commons.utils;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * druid配置文件
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/20 上午10:42
 */
@Data
@ConfigurationProperties(prefix = "spring.datasource.druid")
public class DruidDataSourceProperties {

    private String driverClassName;
    private String url;
    private String username;
    private String password;

    private int initialSize;
    private int minIdle;
    private int maxActive = 100;
    private long maxWait;
    private long timeBetweenEvictionRunsMillis;
    private long minEvictableIdleTimeMillis;
    private String validationQuery;
    private boolean testWhileIdle;
    private boolean testOnBorrow;
    private boolean testOnReturn;
    private boolean poolPreparedStatements;
    private int maxPoolPreparedStatementPerConnectionSize;
    private String filters;

}

配置相关的servlett和filter

监控视图

package com.faraway.yy_commons.utils;

import com.alibaba.druid.support.http.StatViewServlet;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

/**
 * druid监控视图
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/20 上午10:47
 */
@WebServlet(
        urlPatterns = "/druid/*",
        initParams= {
                @WebInitParam(name = "allow", value = "localhost"),// IP白名单 (没有配置或者为空,则允许所有访问)
//                @WebInitParam(name = "deny", value = "192.168.6.73"),// IP黑名单 (存在共同时,deny优先于allow)
                @WebInitParam(name = "loginUsername", value = "admin"),// 用户名
                @WebInitParam(name = "loginPassword", value = "admin"),// 密码
                @WebInitParam(name = "resetEnable", value = "true")// 禁用HTML页面上的“Reset All”功能
        }
)
public class DruidStatViewServlet extends StatViewServlet {

    private static final long serialVersionUID = 7359758657306626394L;
}

监控拦截器

package com.faraway.yy_commons.utils;

import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

/**
 * druid监控拦截器
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/20 上午10:42
 */
@WebFilter(
        filterName = "druidWebStatFilter",
        urlPatterns = "/*",
        initParams = {
                @WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"),// 忽略资源
        }
)
public class DruidStatFilter {


}

网上大多使用配置类的方式配置,在此也贴出,但是无需使用:

package com.garyond.hurricane.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
@EnableConfigurationProperties({DruidDataSourceProperties.class})
public class DruidConfig {
    @Autowired
    private DruidDataSourceProperties properties;

    @Bean
    @ConditionalOnMissingBean
    public DataSource druidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(properties.getDriverClassName());
        druidDataSource.setUrl(properties.getUrl());
        druidDataSource.setUsername(properties.getUsername());
        druidDataSource.setPassword(properties.getPassword());
        druidDataSource.setInitialSize(properties.getInitialSize());
        druidDataSource.setMinIdle(properties.getMinIdle());
        druidDataSource.setMaxActive(properties.getMaxActive());
        druidDataSource.setMaxWait(properties.getMaxWait());
        druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis());
        druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis());
        druidDataSource.setValidationQuery(properties.getValidationQuery());
        druidDataSource.setTestWhileIdle(properties.isTestWhileIdle());
        druidDataSource.setTestOnBorrow(properties.isTestOnBorrow());
        druidDataSource.setTestOnReturn(properties.isTestOnReturn());
        druidDataSource.setPoolPreparedStatements(properties.isPoolPreparedStatements());
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(properties.getMaxPoolPreparedStatementPerConnectionSize());

        try {
            druidDataSource.setFilters(properties.getFilters());
            druidDataSource.init();
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return druidDataSource;
    }

    /**
     * 注册Servlet信息, 配置监控视图
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        //白名单:
        servletRegistrationBean.addInitParameter("allow","192.168.6.195");
        //IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
        servletRegistrationBean.addInitParameter("deny","192.168.6.73");
        //登录查看信息的账号密码, 用于登录Druid监控后台
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "admin");
        //是否能够重置数据.
        servletRegistrationBean.addInitParameter("resetEnable", "true");
        return servletRegistrationBean;

    }

    /**
     * 注册Filter信息, 监控拦截器
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}

查看监控

配置完成后, 并完成相关的数据库操作配置, 启动Spring Boot应用程序,就可以通过访问: http://localhost:8888/druid/index.html 访问Druid监控后台页面。

至此配置完毕

多数据源

springboot默认加载配置文件里的配置,配置规则已经定义为单数据源,想要配置多数据源必须禁用默认加载,

多数据源的思路如下:

配置文件里配置多数据源配置信息
创建配置类读取配置文件创建不同的DataSource
使用数据源的时候根据业务不同用aop切换数据源
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

在启动类添加此注解

配置文件:

#数据源
spring:
  datasource:
    one:
      name: druidDataSource
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://${dbIp}:${dbPort}/${dbName}?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: ${dbUser}
      password: ${dbPwd}

    two:
      name: druidDataSource
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://${dbIp}:${dbPort}/yy_user?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: ${dbUser}
      password: ${dbPwd}

    druid:

  #      配置监控统计拦截的filter , 去掉后监控sql无法统计wall用于防火墙
      filters: stat,wall,log4j,config

  #      最大连接数
      max-active: 100

  #      初始化大小
      initial-size: 1

  #      获取连接等待超时时间
      max-wait: 60000

  #      最小连接数
      min-idle: 1

  #      间隔多久检测一次 检测需要关闭的空闲连接 单位毫秒
      time-between-eviction-runs-millis: 60000
  #      一个连接最小生存时间
      min-evictable-idle-time-millis: 300000
      validation-query: select 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-open-prepared-statements: 50
      max-pool-prepared-statement-per-connection-size: 20

数据源配置类:

package com.faraway.yy_commons.dataSource;

import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 多数据源配置类
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/23 上午10:00
 */
@Configuration
public class DataSourceConfig {

    @Bean(name = "one")
    @ConfigurationProperties(prefix = "spring.datasource.one") // application.properteis中对应属性的前缀
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "two")
    @ConfigurationProperties(prefix = "spring.datasource.two") // application.properteis中对应属性的前缀
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 动态数据源:通过aop在不同的数据源中切换
     *
     * @return
     */
    @Primary
    @Bean(name = "DynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();

        // 默认数据源
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());

        // 配置多数据源
        Map<Object, Object> map = new HashMap<>();
        map.put("one", dataSource1());
        map.put("two", dataSource2());

        dynamicDataSource.setTargetDataSources(map);

        return dynamicDataSource;
    }

    /**
     * 配置@Transactional注解事物
     *
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

数据源切换

package com.faraway.yy_commons.dataSource;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * 保存切换数据源
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/23 上午10:52
 */
@Slf4j
public class DataSourceContextHolder {

    /** 默认数据源 */
    public static final String DEFAULT_DS = "one";

    /**
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
     * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal<String> CONTEXT_HOLDER = new  ThreadLocal<String>();


    /**
     * 管理所有的数据源id,用于数据源的判断
     */
    public static List<String> datasourceId = new ArrayList<String>();


    /**
     * @Title: setDateSoureType
     * @Description: 设置数据源的变量
     * @param dbType
     * @return void
     */
    public static void setDB(String dbType){
        log.info("获取数据源 , 数据源为::" + dbType);
        CONTEXT_HOLDER.set(dbType);
    }

    /**
     * @Title: getDateSoureType
     * @Description: 获得数据源的变量
     * @return String
     */
    public static String getDBType(){
        return CONTEXT_HOLDER.get();
    }

    /**
     * @Title: clearDateSoureType
     * @Description: 清空所有的数据源变量
     * @return void
     */
    public static void clearDBType(){
        CONTEXT_HOLDER.remove();
    }

    /**
     * @Title: existDateSoure
     * @Description: 判断数据源是否已存在
     * @param dbType
     * @return boolean
     */
    public static boolean existDateSoure(String dbType ){
        return datasourceId.contains(dbType);
    }

}


当前数据源

package com.faraway.yy_commons.dataSource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.util.StringUtils;

/**
 * 当前数据源
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/23 上午11:00
 */
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {


    @Override
    protected Object determineCurrentLookupKey() {

        String dbType = DataSourceContextHolder.getDBType();
        if (StringUtils.isEmpty(dbType)) {
            DataSourceContextHolder.setDB("one");
        }
        log.info("当前数据源为:   " + DataSourceContextHolder.getDBType());
        return DataSourceContextHolder.getDBType();
    }
}


数据源切换所用注解:

package com.faraway.yy_commons.dataSource;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author yuanyao@wistronits.com
 * create on 2018/7/23 上午11:08
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DS {

    String value() default "one";
}

切面:

package com.faraway.yy_commons.dataSource;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;


/**
 * 数据源动态切换
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/23 上午11:10
 */
@Slf4j
@Aspect
@Component
public class DynamicDataSourceAspect {



    @Before("@annotation(ds)")
    public void beforeSwitchDS(JoinPoint point,DS ds) {

        try {

            log.info("检测到AOP切面,切换数据源,切换为 , " + ds.value());

            String value = ds.value();
            DataSourceContextHolder.setDB(value);

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }
//
    @After("@annotation(com.faraway.yy_commons.dataSource.DS)")
    public void afterSwitchDS(JoinPoint point) {
        log.info("数据源切换完毕,清除相关信息");
        DataSourceContextHolder.clearDBType();
    }


}

测试:在service中使用

package com.faraway.yy_commons.mybaties.bean.service.impl;

import com.faraway.yy_commons.mybaties.bean.entity.Sys_user;
import com.faraway.yy_commons.mybaties.bean.mapper.Sys_userMapper;
import com.faraway.yy_commons.mybaties.bean.service.ISys_userService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.faraway.yy_commons.dataSource.DS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yuanyao@wistronits.com
 * @since 2018-07-23
 */
@Service
public class Sys_userServiceImpl extends ServiceImpl<Sys_userMapper, Sys_user> implements ISys_userService {

    @Autowired
    Sys_userMapper userMapper;

    @DS("two")
    @Override
    public List<Sys_user> selectAll() {

        List<Sys_user> sys_users = userMapper.selectList(null);
        return sys_users;
    }
}

数据源切换成功

到 druid 监控页面发现页面提示如下:

(*) property for user to setup

是因为上面构建的数据源并没有使用druid,

所以修改数据源配置类:

package com.faraway.yy_commons.dataSource;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 多数据源配置类
 *
 * @author yuanyao@wistronits.com
 * create on 2018/7/23 上午10:00
 */
@Configuration
public class DataSourceConfig {

    @Bean(name = "one")
    @ConfigurationProperties(prefix = "spring.datasource.one") // application.properteis中对应属性的前缀
    public DataSource dataSource1() {
        DruidDataSource build = DruidDataSourceBuilder.create().build();
//        return DataSourceBuilder.create().build();
        return build;
    }


    @Bean(name = "two")
    @ConfigurationProperties(prefix = "spring.datasource.two") // application.properteis中对应属性的前缀
    public DataSource dataSource2() {
        DruidDataSource build = DruidDataSourceBuilder.create().build();
//        return DataSourceBuilder.create().build();
        return build;
    }

    /**
     * 动态数据源:通过aop在不同的数据源中切换
     *
     * @return
     */
    @Primary
    @Bean(name = "DynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();

        // 默认数据源
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());

        // 配置多数据源
        Map<Object, Object> map = new HashMap<>();
        map.put("one", dataSource1());
        map.put("two", dataSource2());

        dynamicDataSource.setTargetDataSources(map);

        return dynamicDataSource;
    }

    /**
     * 配置@Transactional注解事物
     *
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

执行测试代码, 页面成功显示两个数据源.

对于多数据源 , druid配置继承问题暂不研究

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值