1. 程式人生 > 實用技巧 >Spring Boot整合Sharding-JDBC實現分庫分表+讀寫分離org.apache.shardingsphere+mybatis-plus(4)

Spring Boot整合Sharding-JDBC實現分庫分表+讀寫分離org.apache.shardingsphere+mybatis-plus(4)

在本文中使用Spring Boot 2.4.1+MyBatis-plus+Druid+Sharding-JDBC+MySQL進行讀寫分離的案件講解。

1、資料庫準備

1、192.168.8.162 test1主

2、192.168.8.134 test1從

3、192.168.8.176 test1從

4、192.168.8.162 test2主

5、192.168.8.134 test2從

6、192.168.8.176 test2從

2、準備分庫分表

USE `test1`;

DROP TABLE IF EXISTS `t_user_0`;
CREATE TABLE `t_user_0` (
  `id` int(10) NOT NULL,
  `name` varchar(50) NOT NULL,
  `sex` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_user_1`;
CREATE TABLE `t_user_1` (
  `id` int(10) NOT NULL,
  `name` varchar(50) NOT NULL,
  `sex` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_user_2`;
CREATE TABLE `t_user_2` (
  `id` int(10) NOT NULL,
  `name` varchar(50) NOT NULL,
  `sex` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_user_3`;
CREATE TABLE `t_user_3` (
  `id` int(10) NOT NULL,
  `name` varchar(50) NOT NULL,
  `sex` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


USE `test2`;

DROP TABLE IF EXISTS `t_user_0`;
CREATE TABLE `t_user_0` (
  `id` int(10) NOT NULL,
  `name` varchar(50) NOT NULL,
  `sex` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_user_1`;
CREATE TABLE `t_user_1` (
  `id` int(10) NOT NULL,
  `name` varchar(50) NOT NULL,
  `sex` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_user_2`;
CREATE TABLE `t_user_2` (
  `id` int(10) NOT NULL,
  `name` varchar(50) NOT NULL,
  `sex` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_user_3`;
CREATE TABLE `t_user_3` (
  `id` int(10) NOT NULL,
  `name` varchar(50) NOT NULL,
  `sex` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3、上程式碼

1、pom.xml配置引入maven依賴

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <druid.version>1.1
.9</druid.version> <mybatis-plus.version>3.1.1</mybatis-plus.version> <mybatis-plus-stater.version>3.1.2</mybatis-plus-stater.version> <lombok.version>1.16.18</lombok.version> <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version> </properties> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true
</optional> </dependency> <!-- druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <!-- Mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatisplus-spring-boot-starter</artifactId> <version>${mybatisplus-spring-boot-starter.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus-stater.version}</version> </dependency> <!--shardingsphere資料分片、脫敏工具--> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.0</version> </dependency>

2、在application.yml中配置使用mybatis-plus及引用資料來源及分庫分表資訊

spring:
 # 配置說明地址 https://test1.apache.org/document/legacy/4.x/document/cn/manual/sharding-jdbc/configuration/config-spring-boot/#%E6%95%B0%E6%8D%AE%E5%88%86%E7%89%87
  shardingsphere:
   # 資料庫
    datasource:
     # 主庫1 ,master資料庫
      master0:
        ###  資料來源類別
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.8.162:3306/test1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: root
        password: root
       # 主庫1從庫1 ,slave資料庫
      master0slave0:
        ###  資料來源類別
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.8.134:3306/test1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: root
        password: root
       # 主庫1從庫2 ,slave資料庫
      master0slave1:
        ###  資料來源類別
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.8.176:3306/test1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: root
        password: root
         # 主庫2 ,master資料庫
      master1:
        ###  資料來源類別
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.8.162:3306/test2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: root
        password: root
       # 主庫2從庫1 ,slave資料庫
      master1slave0:
        ###  資料來源類別
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.8.134:3306/test2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: root
        password: root
       # 主庫2從庫2 ,slave資料庫
      master1slave1:
        ###  資料來源類別
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.8.176:3306/test2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: root
        password: root
        # 資料庫的別名
      names: master0,master0slave0,master0slave1,master1,master1slave0,master1slave1
    sharding:
      # 設定繫結表,用逗號分割
      binding-tables: t_user
      master-slave-rules:
        ds0:
          name: ds0datasource
      # 查詢時的負載均衡演算法,目前有2種演算法,round_robin(輪詢)和random(隨機),
      # 演算法介面是io.shardingjdbc.core.api.algorithm.masterslave.MasterSlaveLoadBalanceAlgorithm。
      # 實現類有RandomMasterSlaveLoadBalanceAlgorithm 和 RoundRobinMasterSlaveLoadBalanceAlgorithm。
          load-balance-algorithm-type: round_robin
       # 主資料來源名稱
          master-data-source-name: master0
          # 從資料來源名稱,多個用逗號隔開
          slave-data-source-names: master0slave0, master0slave1
        ds1:
          name: ds1datasource
      # 查詢時的負載均衡演算法,目前有2種演算法,round_robin(輪詢)和random(隨機),
      # 演算法介面是io.shardingjdbc.core.api.algorithm.masterslave.MasterSlaveLoadBalanceAlgorithm。
      # 實現類有RandomMasterSlaveLoadBalanceAlgorithm 和 RoundRobinMasterSlaveLoadBalanceAlgorithm。
          load-balance-algorithm-type: round_robin
       # 主資料來源名稱
          master-data-source-name: master1
          # 從資料來源名稱,多個用逗號隔開
          slave-data-source-names: master1slave0,master1slave1
      tables:
        ### t_user分庫分表配置
        t_user:
          actual-data-nodes: ds$->{0..1}.t_user_$->{0..3}
          database-strategy:
            standard:
              precise-algorithm-class-name: com.demo.shardingjdbc.MyDBPreciseShardingAlgorithm
              sharding-column: id
          table-strategy:
            standard:
              precise-algorithm-class-name: com.demo.shardingjdbc.MyTablePreciseShardingAlgorithm
              sharding-column: id
#### mybatis-plus ###
mybatis-plus:
  # 如果是放在src/main/java目錄下 classpath:/com/yourpackage/*/mapper/*Mapper.xml
  # 如果是放在resource目錄 classpath:/mapper/*Mapper.xml
  mapper-locations: classpath:mapper/*.xml
  #實體掃描,多個package用逗號或者分號分隔
  type-aliases-package: com.demo.shardingjdbc.entity
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
  #主鍵型別  0:"資料庫ID自增", 1:"使用者輸入ID",2:"全域性唯一ID (數字型別唯一ID)", 3:"全域性唯一ID UUID";
  global-config:
    db-config:
      id-type: auto
      #欄位策略 0:"忽略判斷",1:"非 NULL 判斷"),2:"非空判斷"
      field-strategy: not-empty
      #駝峰下劃線轉換
      column-underline: true
      #邏輯刪除配置
      logic-delete-value: 0
      logic-not-delete-value: 1
      db-type: mysql
  #重新整理mapper 除錯神器
  refresh: false

3、配置分庫分表分片規則(結合application.yml)

分庫規則(結合pplication.yml中database-strategy)

package com.demo.shardingjdbc;



import java.util.Collection;

import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

/**
 * 自定義實現 精準分片演算法(PreciseShardingAlgorithm)介面
 * 資料表table的精準分片
 * @author hzy
 *
 */
public class MyDBPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) {
        for (String tableName : availableTargetNames) {
            if (tableName.endsWith(shardingValue.getValue() % 2 + "")) {
                return tableName;
            }
        }
        throw new IllegalArgumentException();
    }

}

分表規則(結合pplication.yml中table-strategy)

package com.demo.shardingjdbc;



import java.util.Collection;

import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

/**
 * 自定義實現 精準分片演算法(PreciseShardingAlgorithm)介面
 * 資料表table的精準分片
 * @author hzy
 *
 */
public class MyTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) {
        for (String tableName : availableTargetNames) {
            if (tableName.endsWith(shardingValue.getValue() % 4 + "")) {
                return tableName;
            }
        }
        throw new IllegalArgumentException();
    }

}

4、mybatis-plus操作資料庫配置

User.java

package com.demo.shardingjdbc.entity;

import java.io.Serializable;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import lombok.Data;

/**
 * @Description: (User)實體類
 * @Version 1.0
 */
@Data
@TableName("t_user")
public class User implements Serializable {

    private static final long serialVersionUID = 358157380505039579L;

    /**
     * 使用者id
     */
    @TableId(type = IdType.INPUT)
    private Integer id;

    /**
     * 使用者名稱稱
     */
    private String name;


    /**
     * 性別
     */
    private String sex;

}

mapper

package com.demo.shardingjdbc.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.shardingjdbc.entity.User;

/**
 * (t_user)表資料庫訪問層
 *
 */
public interface UserMapper extends BaseMapper<User> {

}

5、mybatis-plus配置MybatisPlusConfig

package com.demo.shardingjdbc.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @Description:
 */

//Spring boot方式
@EnableTransactionManagement
@Configuration
//掃描的mapper檔案路徑
@MapperScan(value = "com.demo.shardingjdbc.mapper")
public class MybatisPlusConfig {

    /**
     * 分頁外掛
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

6、service層

package com.demo.shardingjdbc.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.demo.shardingjdbc.entity.User;
import com.demo.shardingjdbc.mapper.UserMapper;
import com.demo.shardingjdbc.service.UserService;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> selectList() {
        QueryWrapper<User> wrapper = new QueryWrapper<User>();
        wrapper.orderByAsc("id");
        List<User> users = userMapper.selectList(wrapper);
        return users;
    }

    @Override
    public int insert(User user) {
        return userMapper.insert(user);
    }

}

7、controller控制層

package com.demo.shardingjdbc.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.demo.shardingjdbc.entity.User;
import com.demo.shardingjdbc.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName TestController
 * @Description TestController
 * @Version
 */
@RestController
@Slf4j
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 使用者列表
     * 
     * @return
     */
    @RequestMapping("/userList")
    public List<User> userList() {
        log.info("********TestController userList()");
        List<User> users = userService.selectList();
        return users;
    }

    /**
     * 儲存使用者
     * 
     * @return
     */
    @GetMapping("/add")
    public Object add() {
        int num = 0;
        for (int i = 1; i <= 300; i++) {
            User user = new User();
            user.setId(i);
            user.setName("hzy" + (i));
            String sex = (i % 2 == 0) ? "男" : "女";
            user.setSex(sex);

            int resutl = userService.insert(user);
            log.info("insert:" + user.toString() + " result:" + resutl);
            num = num + resutl;
        }
        return num;
    }
}

完成。在瀏覽器上執行localhost:8080/add,然後去資料庫中查詢,可以看到test1.t_user_0、test1.t_user_2、test2.t_user_1、test2.t_user_3分別插入了資料。

然後訪問localhost:8080/userList,可以查詢資料庫中四個表中的所有資料。可見Sharding-JDBC在插入資料的時候,根據資料分庫分表策略,將資料儲存在不同庫不同表中,查詢時將資料庫從多個表中查詢並聚合。