springboot系列-mysql多数据源

在实际系统开发中有时一个程序可能需要连接多个数据库,这就用到了多数据功能,废话多说直接上代码…
1.配置文件

# 数据源
db:
  mysql:
    driverClassName:  com.mysql.jdbc.Driver
m1:
  datasource:
    password: 123456
    url: jdbc:mysql://localhost:3306/m1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
    username: root
s1:
  datasource:
    password: TESTDB2020!pubaogz.com
    url: jdbc:mysql://localhost:3306/s1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
    username: root
# 连接池参数,可以不用配置 由dba在数据库层统一控制
m1pool:
  datasource:
    initialSize: 20
    maxActive: 200
    maxPoolPreparedStatementPerConnectionSize: 20
    maxWait: 60000
    minEvictableIdleTimeMillis: 300000
    minIdle: 20
    poolPreparedStatements: true
    testOnBorrow: false
    testOnReturn: false
    testWhileIdle: true
    timeBetweenEvictionRunsMillis: 60000
m2:
  datasource:
    password: TESTDB2020!pubaogz.com
    url: jdbc:mysql://localhost:3306/m2?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
    username: root
s2:
  datasource:
    password: 123456
    url: jdbc:mysql://localhost:3306/s2?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
    username: root
# 连接池参数,可以不用配置 由dba在数据库层统一控制 
m2pool:
  datasource:
    initialSize: 20
    maxActive: 200
    maxPoolPreparedStatementPerConnectionSize: 20
    maxWait: 60000
    minEvictableIdleTimeMillis: 300000
    minIdle: 20
    poolPreparedStatements: true
    testOnBorrow: false
    testOnReturn: false
    testWhileIdle: true
    timeBetweenEvictionRunsMillis: 60000
  1. Druid 监控
package com.app.db.datasource;

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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;

/**
 * Druid 控制台
 * @author liuli
 */
@Configuration
public class DruidServletConfig {
    /**
     * 注册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;
    }

}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.关键类

@Configuration
@MapperScan(basePackages = DataSourceConstant.M1_PACKAGE, sqlSessionFactoryRef = "m1SqlSessionFactory")
/**
 * 数据源配置
 * @author liuli
 */
public class M1DataSourceConfig {
    /**M1*/
    @Value("${m1.datasource.url}")
    private String m1Url;
    @Value("${m1.datasource.username}")
    private String m1User;
    @Value("${m1.datasource.password}")
    private String m1Password;
    /**S1*/
    @Value("${s1.datasource.url}")
    private String s1Url;
    @Value("${s1.datasource.username}")
    private String s1User;
    @Value("${s1.datasource.password}")
    private String s1Password;
    /**驱动*/
    @Value("${db.mysql.driverClassName}")
    private String driverClass;
    /**pool*/
    @Value("${m1pool.datasource.maxActive}")
    private Integer maxActive;
    @Value("${m1pool.datasource.minIdle}")
    private Integer minIdle;
    @Value("${m1pool.datasource.initialSize}")
    private Integer initialSize;
    @Value("${m1pool.datasource.maxWait}")
    private Long maxWait;
    @Value("${m1pool.datasource.timeBetweenEvictionRunsMillis}")
    private Long timeBetweenEvictionRunsMillis;
    @Value("${m1pool.datasource.minEvictableIdleTimeMillis}")
    private Long minEvictableIdleTimeMillis;
    @Value("${m1pool.datasource.testWhileIdle}")
    private Boolean testWhileIdle;
    @Value("${m1pool.datasource.testWhileIdle}")
    private Boolean testOnBorrow;
    @Value("${m1pool.datasource.testOnBorrow}")
    private Boolean testOnReturn;
    @Value("${m2pool.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private Integer maxPoolPreparedStatementPerConnectionSize;

    @Bean(name = "m1DataSource")
    @Primary
    public DataSource m1DataSource() {
        M1DynamicDataSource dynamicDataSource = M1DynamicDataSource.getInstance();
        DruidDataSource masterDataSource = new DruidDataSource();
        masterDataSource.setDriverClassName(driverClass);
        masterDataSource.setUrl(m1Url);
        masterDataSource.setUsername(m1User);
        masterDataSource.setPassword(m1Password);
        //连接池配置
        masterDataSource.setMaxActive(maxActive);
        masterDataSource.setMinIdle(minIdle);
        masterDataSource.setInitialSize(initialSize);
        masterDataSource.setMaxWait(maxWait);
        masterDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        masterDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        masterDataSource.setTestWhileIdle(testWhileIdle);
        masterDataSource.setTestOnBorrow(testOnBorrow);
        masterDataSource.setTestOnReturn(testOnReturn);
        masterDataSource.setValidationQuery("SELECT 'x'");
        masterDataSource.setPoolPreparedStatements(true);
        masterDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        //监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
        try {
            masterDataSource.setFilters("stat,wall");
        } catch (SQLException e) {
        }
        DruidDataSource slaveDataSource = new DruidDataSource();
        slaveDataSource.setDriverClassName(driverClass);
        slaveDataSource.setUrl(s1Url);
        slaveDataSource.setUsername(s1User);
        slaveDataSource.setPassword(s1Password);
        //连接池配置
        slaveDataSource.setMaxActive(maxActive);
        slaveDataSource.setMinIdle(minIdle);
        slaveDataSource.setInitialSize(initialSize);
        slaveDataSource.setMaxWait(maxWait);
        slaveDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        slaveDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        slaveDataSource.setTestWhileIdle(testWhileIdle);
        slaveDataSource.setTestOnBorrow(testOnBorrow);
        slaveDataSource.setTestOnReturn(testOnReturn);
        slaveDataSource.setValidationQuery("SELECT 'x'");
        slaveDataSource.setPoolPreparedStatements(true);
        slaveDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        try {
            //通过别名的方式配置扩展插件,常用的插件有:
            //监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
            slaveDataSource.setFilters("stat,wall");
        } catch (SQLException e) {
        }
        Map<Object,Object> map = new HashMap<>();
        map.put(DataSourceConstant.DB_MASTER1, masterDataSource);
        map.put(DataSourceConstant.DB_SLAVE1, slaveDataSource);
        dynamicDataSource.setTargetDataSources(map);
        // 默认数据源 MASTER
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
        return dynamicDataSource;
    }

    @Bean(name = "m1TransactionManager")
    @Primary
    public DataSourceTransactionManager m1TransactionManager() {
        return new DataSourceTransactionManager(m1DataSource());
    }

    @Bean(name = "m1SqlSessionFactory")
    @Primary
    public SqlSessionFactory m1SqlSessionFactory(@Qualifier("m1DataSource") DataSource m1DataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(m1DataSource);
        sessionFactory.setTypeAliasesPackage(DataSourceConstant.M1_PACKAGE);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(DataSourceConstant.M1_MAPPER_LOCATION));
        return sessionFactory.getObject();
    }



/**
 * db1 数据源切换
 * @author liuli
 */
public class M1DataBaseContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    private static Logger log = LoggerFactory.getLogger(M1DataBaseContextHolder.class);
    /**切换主库*/
    public static void setMaster() {
        contextHolder.set(DataSourceConstant.DB_MASTER1);
    }
    /**切换从库*/
    public static void setSalve() {
        contextHolder.set(DataSourceConstant.DB_SLAVE1);
    }
    /**获取数据源*/
    public static String getDBKey() {
        return contextHolder.get();
    }
    /**清除数据源*/
    public static void clearDBKey() {
        contextHolder.remove();
    }

}



/**
 * 动态数据源
 * @author liuli
 *
 */
public class M1DynamicDataSource extends AbstractRoutingDataSource {
    private static M1DynamicDataSource instance;
    private static byte[] lock=new byte[0];
    private static Map<Object,Object> dataSourceMap=new HashMap<Object, Object>();

    @Override
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        super.setTargetDataSources(targetDataSources);
        dataSourceMap.putAll(targetDataSources);
        // 必须添加该句,否则新添加数据源无法识别到
        super.afterPropertiesSet();
    }

    public Map<Object, Object> getDataSourceMap() {
        return dataSourceMap;
    }

    @Override
    protected Object determineCurrentLookupKey() {
        String dbKey = M1DataBaseContextHolder.getDBKey();
		/*if (StringUtils.isBlank(dbKey)) {
			dbKey = "read";
		}*/
        return dbKey;
    }

    private M1DynamicDataSource() {}

    public static synchronized M1DynamicDataSource getInstance(){
        if(instance==null){
            synchronized (lock){
                if(instance==null){
                    instance=new M1DynamicDataSource();
                }
            }
        }
        return instance;
    }

}

源代码参考:
https://github.com/472732787/com-spring-multiple-datasource/tree/master/multiple-datasource-mysql

要在Spring Boot中配置多数据源使用mybatis-plus,你可以按照以下步骤进行操作: 1. 首先,在`application.properties`(或`application.yml`)文件中配置你的数据源信息。假设你有两个数据源,分别为`datasource1`和`datasource2`,你可以在配置文件中添加以下内容: ```properties # 数据源1 spring.datasource.datasource1.url=jdbc:mysql://localhost:3306/db1 spring.datasource.datasource1.username=username1 spring.datasource.datasource1.password=password1 spring.datasource.datasource1.driver-class-name=com.mysql.jdbc.Driver # 数据源2 spring.datasource.datasource2.url=jdbc:mysql://localhost:3306/db2 spring.datasource.datasource2.username=username2 spring.datasource.datasource2.password=password2 spring.datasource.datasource2.driver-class-name=com.mysql.jdbc.Driver ``` 2. 创建两个数据源的配置类,用于配置和管理数据源。例如,创建`DataSource1Config`和`DataSource2Config`类,并在类上添加注解`@Configuration`。 ```java @Configuration public class DataSource1Config { @Bean(name = "dataSource1") @ConfigurationProperties(prefix = "spring.datasource.datasource1") public DataSource dataSource1() { return DataSourceBuilder.create().build(); } } @Configuration public class DataSource2Config { @Bean(name = "dataSource2") @ConfigurationProperties(prefix = "spring.datasource.datasource2") public DataSource dataSource2() { return DataSourceBuilder.create().build(); } } ``` 3. 创建两个`SqlSessionFactory`,分别指定对应的数据源。 ```java @Configuration @MapperScan(basePackages = "com.example.mapper1", sqlSessionFactoryRef = "sqlSessionFactory1") public class MybatisPlusConfig1 { @Autowired @Qualifier("dataSource1") private DataSource dataSource1; @Bean(name = "sqlSessionFactory1") public SqlSessionFactory sqlSessionFactory1() throws Exception { MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean(); factoryBean.setDataSource(dataSource1); return factoryBean.getObject(); } } @Configuration @MapperScan(basePackages = "com.example.mapper2", sqlSessionFactoryRef = "sqlSessionFactory2") public class MybatisPlusConfig2 { @Autowired @Qualifier("dataSource2") private DataSource dataSource2; @Bean(name = "sqlSessionFactory2") public SqlSessionFactory sqlSessionFactory2() throws Exception { MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean(); factoryBean.setDataSource(dataSource2); return factoryBean.getObject(); } } ``` 4. 创建两个事务管理器,分别指定对应的数据源。 ```java @Configuration public class TransactionManager1Config { @Autowired @Qualifier("dataSource1") private DataSource dataSource1; @Bean(name = "transactionManager1") public DataSourceTransactionManager transactionManager1() { return new DataSourceTransactionManager(dataSource1); } } @Configuration public class TransactionManager2Config { @Autowired @Qualifier("dataSource2") private DataSource dataSource2; @Bean(name = "transactionManager2") public DataSourceTransactionManager transactionManager2() { return new DataSourceTransactionManager(dataSource2); } } ``` 5. 最后,你可以在你的Mapper接口上使用`@Qualifier`注解指定使用哪个数据源。 ```java @Mapper public interface UserMapper1 { @Select("SELECT * FROM user") @Qualifier("sqlSessionFactory1") List<User> findAll(); } @Mapper public interface UserMapper2 { @Select("SELECT * FROM user") @Qualifier("sqlSessionFactory2") List<User> findAll(); } ``` 这样,你就成功配置了多数据源的mybatis-plus。请根据实际需求修改配置和代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值