SpringBoot多数据源及读写分离实现

135 阅读3分钟

一、SpringBoot的多数据源

在日常项目中,避免不了会用到多数据源或者读写分离的实现,下面来看一下如何实现

1-1、基础准备-创建一个springboot父级项目

首先创建一个springboot项目作为Parent项目,然后引入相关pom依赖,最终pom内容如下: 主要需要引入mysql驱动、drui数据源、mybatis-plus

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.jony</groupId>
    <artifactId>readwrite</artifactId>
    <version>1.0</version>
    <name>readwrite</name>
    <description>readwrite</description>
    <packaging>pom</packaging>

    <modules>
        <module>DynamicDS</module>
    </modules>

    <properties>
        <java.version>17</java.version>
        <spring-boot.version>2.7.8</spring-boot.version>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--mysql 驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>

        <!--drui连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.11</version>
        </dependency>

        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>

            <!--spring boot 的版本管理-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

1-2、在Controller层指定数据源

1-2-1、创建一个module项目

给父项目创建一个module设置名称为:DynamicDS,其中pom的内容如下(pom中的parent引入父项目)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.jony</groupId>
        <artifactId>readwrite</artifactId>
        <version>1.0</version>
    </parent>
    <groupId>com.jony</groupId>
    <artifactId>DynamicDS</artifactId>
    <version>1.0</version>
    <name>DynamicDS</name>
    <description>DynamicDS</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

1-2-2、配置数据源

暂时设置两个数据源(datasource1及datasource2),如下:

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    #自定义第一个数据源
    datasource1:
      url: jdbc:mysql://localhost:3306/coursedb?serverTimezone=UTC
      username: root
      password: root
      initial-size: 1
      min-idle: 1
      max-active: 20
      test-on-borrow: true
      driver-class-name: com.mysql.cj.jdbc.Driver
    #自定义第二个数据源
    datasource2:
      url: jdbc:mysql://localhost:3306/coursedb2?serverTimezone=UTC
      username: root
      password: root
      initial-size: 1
      min-idle: 1
      max-active: 20
      test-on-borrow: true
      driver-class-name: com.mysql.cj.jdbc.Driver

1-2-3、加载数据源

创建一个加载数据源的类,并且添加@Configuration注解,最终代码如下:

@Configuration
public class DataSourceConfig {

    @Bean(name = "dataSource1")
    @ConfigurationProperties(prefix = "spring.datasource.datasource1")
    public DataSource dataSource1() {
        // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "spring.datasource.datasource2")
    public DataSource dataSource2() {
        // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
        return DruidDataSourceBuilder.create().build();
    }
}

以上代码主要读取配置文件,完成数据源的加载,并且通过@Bean指定Bean的名称

1-2-4、读取数据库,及设置默认数据源

使用AbstractRoutingDataSource创建两个库,R表示读库,W表示写库。同时设置dataSource1为默认数据源,防止未指定数据源报错。

@Component("dynamicDataSource")
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {

    public static ThreadLocal<String> name = new ThreadLocal<String>();
    @Override
    protected Object determineCurrentLookupKey() {
        return name.get();
    }

    @Resource(name = "dataSource1")
    DataSource dataSource1;
    @Resource(name = "dataSource2")
    DataSource dataSource2;

    @Override
    public void afterPropertiesSet() {
        // 为targetDataSources初始化所有数据源
        Map<Object, Object> targetDataSources=new HashMap<Object,Object>();
        targetDataSources.put("R",dataSource1);
        targetDataSources.put("W",dataSource2);

        super.setTargetDataSources(targetDataSources);

        // 为defaultTargetDataSource 设置默认的数据源
        super.setDefaultTargetDataSource(dataSource1);

        super.afterPropertiesSet();
    }
}

1-2-5、Controller中设置使用的数据源

@Controller
@RequestMapping("/RDS")
public class CourseControllerRDS {
    @Resource
    CourseMapper courseMapper;

    @ResponseBody
    @RequestMapping("/queryCourse")
    public Object queryOrder(@RequestParam(value = "dsKey",defaultValue = "R") String dsKey){
        DynamicDataSource.name.set(dsKey);
        return courseMapper.selectList(null);
    }

    @ResponseBody
    @RequestMapping("/createCourse")
    public String createCourse(@RequestParam(value = "dsKey",defaultValue = "W") String dsKey, Course course){
        DynamicDataSource.name.set(dsKey);
        courseMapper.insert(course);
        return "SUCCESS BY RDS";
    }
}

1-3、使用dynamic-datasource在Service中指定数据源

1-3-1、创建module项目

同样创建一个module,其pom和上面创建的类似,以父项目作为parent,同时添加baomidoudynamic-datasource-spring-boot-starter

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.jony</groupId>
        <artifactId>readwrite</artifactId>
        <version>1.0</version>
    </parent>
    <groupId>com.jony</groupId>
    <artifactId>DSFrameWork</artifactId>
    <version>1.0</version>
    <name>DSFrameWork</name>
    <description>DSFrameWork</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-core -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-core</artifactId>
            <version>3.0.5</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.6.3</version>
            </plugin>
        </plugins>
    </build>

</project>

1-3-2、配置数据源

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    #使用dynamicDatasource框架
    dynamic:
      #设置默认的数据源或者数据源组,read
      primary: read
      #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      strict: false
      datasource:
        read:
          url: jdbc:mysql://localhost:3306/coursedb?serverTimezone=UTC
          username: root
          password: root
          initial-size: 1
          min-idle: 1
          max-active: 20
          test-on-borrow: true
          driver-class-name: com.mysql.cj.jdbc.Driver
        write:
          url: jdbc:mysql://localhost:3306/coursedb2?serverTimezone=UTC
          username: root
          password: root
          initial-size: 1
          min-idle: 1
          max-active: 20
          test-on-borrow: true
          driver-class-name: com.mysql.cj.jdbc.Driver

1-3-3、数据源设置

在service中通过设置@DS注解,就可以设置当前文件的数据源,在方法中也可以通过@DS来设置数据源,方法的设置优先级高于类上的设置

@Service
@DS("write")
public class CourseService {

    @Resource
    private JdbcTemplate jdbcTemplate;

//    @DS("read")
    public List selectCourse(){
        return jdbcTemplate.queryForList("select * from course");
    }

    @DS("read")
    public int createCourse(Course course){
        return jdbcTemplate.update("insert into course values(?,?,?,?)",course.getCid(),course.getCname(),course.getUserId(),course.getCstatus());
    }
}

到此两种数据源配置的方法就介绍完毕了