SpringBoot配置多个数据源-详解

一直在趟坑,从未被超越。
借鉴文章
个人觉得我算是整理的比较详细的了,有些博客老是缺斤少两的。最恶心的是竟然会有人写到,如需下文请关注什么什么公众号。

结构
在这里格式图片描述
pom文件

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- druid数据源驱动 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.0</version>
        </dependency>
        <!-- 通用mapper -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>1.1.5</version>
        </dependency>
        <!-- druid监控依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.28</version>
        </dependency>

    </dependencies>

连接池配置

package com.example.demo.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;

@Configuration
@SuppressWarnings("AlibabaRemoveCommentedCode") //该注解主要用在取消一些编译器产生的警告
public class DruidConfig {

    /**
     * http://localhost:8080/druid/login.html
     * 注册一个StatViewServlet
     *
     * @return
     */
    @Bean
    public ServletRegistrationBean DruidStatViewServle() {

        //org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        //白名单:
        servletRegistrationBean.addInitParameter("allow", "127.0.0.1");
        //登录查看信息的账号密码.
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "123456");

        //是否能够重置数据.
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;
    }

    /**
     * 注册一个:filterRegistrationBean
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean druidStatFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());

        //添加过滤规则.
        filterRegistrationBean.addUrlPatterns("/*");

        //添加不需要忽略的格式信息.
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");

        return filterRegistrationBean;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
}

首先配置两个数据源连接,格式如下(网上url连接大多用jdbc-url连接,经测试并不好使,也可能是我测试的有问题。如果有兴趣你们也可以多种方式自测一下)
记得启动类不要加@MapperScan("")扫描你的mapper层,因为多数据源连接的核心配置就在于自己创建自己的mappe层,自己扫描自己的。

server.port=8081
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver

spring.datasource.url=jdbc:mysql://192.168.0.1:3306/game?useUnicode=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

spring.datasource.url2=jdbc:mysql://192.168.0.2:3306/vip?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Hongkong
spring.datasource.username2=root
spring.datasource.password2=root

spring.jpa.open-in-view=false
#数据库连接池初始化连接个数
spring.datasource.druid.initial-size=5
#最小连接个数
spring.datasource.druid.min-idle=5
#最大的连接数
spring.datasource.druid.max-active=20
#等待连接获取的最大等待时间
spring.datasource.druid.max-wait=6000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=30000
#检测连接是否有效的sql
spring.datasource.validationQuery=SELECT 1 FROM DUAL
#申请连接时检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效(不影响性能)
spring.datasource.testWhileIdle=true
#申请连接时不检测连接是否有效
spring.datasource.testOnBorrow=false
#归还连接时不检测连接是否有效
spring.datasource.testOnReturn=false
#打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
#配置监控统计拦截的filters(不配置则监控界面sql无法统计),监控统计filter:stat,日志filter:log4j,防御sql注入filter:wall
spring.datasource.druid.filters=stat,log4j,wall
#支持合并多个DruidDataSource的监控数据
spring.datasource.druid.use-global-data-source-stat=true
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

各自配置扫描文件

注解备注
@Primary优先方案,被注解的实现,优先被注入 。主要用来标注哪个数据源为主数据源,有且只能标注一个
@Qualifier先声明后使用,相当于多个实现起多个不同的名字,注入时候告诉我你要注入哪个

主数据源配置

package com.example.demo.config;


import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = MasterDbConfig.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDbConfig {
	//定义mapperscan需要扫描的mapper层
    static final String PACKAGE = "com.example.demo.mapper.master";
    //定义需要扫描的对应的xml层,在定义好的目录下各自创建文件就可以了
    private static final String MAPPER_LOCATION = "classpath*:mappers/master/*.xml";

    @Value("${spring.datasource.url}")
    private String dbUrl;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.password}")
    private String password;
    @Value("${spring.datasource.driverClassName}")
    private String driverClassName;


    @Bean(name = "masterDataSource")   //声明其为Bean实例
    @Primary  //在同样的DataSource中,首先使用被标注的DataSource
    public DataSource masterDataSource() {
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(this.dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);
        return datasource;
    }

    @Bean(name = "masterTransactionManager")
    @Primary
    public DataSourceTransactionManager masterTransactionManager() {
        return new DataSourceTransactionManager(masterDataSource());
    }

    @Bean(name = "masterSqlSessionFactory")
    @Primary
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(masterDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(MasterDbConfig.MAPPER_LOCATION));
        //mybatis 数据库字段与实体类属性驼峰映射配置
        sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
        return sessionFactory.getObject();
    }
}

备数据源配置

package com.example.demo.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;


@Configuration
@MapperScan(basePackages = ClusterDbConfig.PACKAGE, sqlSessionFactoryRef = "clusterSqlSessionFactory")
public class ClusterDbConfig {

    // 精确到 cluster 目录,以便跟其他数据源隔离
    static final String PACKAGE = "com.example.demo.mapper.cluster";
   
    private static final String MAPPER_LOCATION = "classpath*:mappers/cluster/*.xml";
    @Value("${spring.datasource.url2}")
    private String dbUrl;

    @Value("${spring.datasource.username2}")
    private String username;

    @Value("${spring.datasource.password2}")
    private String password;

    @Value("${spring.datasource.driverClassName}")
    private String driverClassName;


    @Bean(name = "clusterDataSource")   //声明其为Bean实例
    public DataSource clusterDataSource() {
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(this.dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);
        return datasource;
    }

    @Bean(name = "clusterTransactionManager")
    public DataSourceTransactionManager clusterTransactionManager() {
        return new DataSourceTransactionManager(clusterDataSource());
    }

    @Bean(name = "clusterSqlSessionFactory")
    public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("clusterDataSource") DataSource culsterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(culsterDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(ClusterDbConfig.MAPPER_LOCATION));
        //mybatis 数据库字段与实体类属性驼峰映射配置
        sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
        return sessionFactory.getObject();
    }
}

创建各自的mappe层和xml文件
自己注意一下namespace就可以了,别把命名空间搞错了

package com.example.demo.mapper.master;

import java.util.HashMap;
import java.util.List;

public interface MasterMapper {
    List<HashMap<String,Object>> queryBooks();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.master.MasterMapper">

    <select id="queryBooks" resultType="java.util.HashMap">
        select * from books
    </select>
</mapper>

Service层,在这个地方就可以自己处理各自的业务啦

package com.example.demo.service;

import com.example.demo.mapper.cluster.ClusterMapper;
import com.example.demo.mapper.master.MasterMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;

@Service
public class TestService {

    @Resource
    private ClusterMapper clusterMapper;
    @Resource
    private MasterMapper masterMapper;

    public List<HashMap<String, Object>> queryBooks() {
        return masterMapper.queryBooks();
    }

    public List<HashMap<String, Object>> queryOrders() {
        return clusterMapper.queryOrders();
    }
}

Controller层

package com.example.demo.controller;

import com.example.demo.service.TestService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping(value = "/test", method = RequestMethod.POST)
public class TestController {
    @Resource
    private TestService testService;

    @RequestMapping("/books")
    public List<HashMap<String, Object>> queryBooks() {
        return testService.queryBooks();
    }

    @RequestMapping("/orders")
    public List<HashMap<String, Object>> queryOrders() {
        return testService.queryOrders();
    }
}
posted @ 2022-01-20 23:22  暮雨寒冬  阅读(311)  评论(0编辑  收藏  举报