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

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

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依賴

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

        <!--springboot整合mybatis的依賴 -->
        <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- 這裡用的是sharding-jdbc-spring-boot-starter 需要注意的是,此時druid不能用spring-boot-starter版本的,需要用正常的包: -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>3.1.0.M1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

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

mybatis.config-location: classpath:META-INF/mybatis-config.xml
spring:
  profiles:
    active: sharding-tbl-ms
  main:
    allow-bean-definition-overriding: true
sharding:
  jdbc:
         ### 資料庫
    dataSource:
          ### 資料庫的別名
      names: ds-master-0,ds-master-1,ds-master-0-slave-0,ds-master-0-slave-1,ds-master-1-slave-0,ds-master-1-slave-1
       # 主庫1 ,master資料庫
      ds-master-0: 
         ###  資料來源類別
        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
        maxPoolSize: 20
         ### 主庫1從庫1 ,slave資料庫
      ds-master-0-slave-0:
         ###  資料來源類別
        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
        maxPoolSize: 20
        ### 主庫1從庫1 ,slave資料庫
      ds-master-0-slave-1:
         ###  資料來源類別
        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
        maxPoolSize: 20
        # 主庫2 ,master資料庫
      ds-master-1: 
         ###  資料來源類別
        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
        maxPoolSize: 20
         ### 主庫2從庫1 ,slave資料庫
      ds-master-1-slave-0:
         ###  資料來源類別
        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
        maxPoolSize: 20
        ### 主庫2從庫2 ,slave資料庫
      ds-master-1-slave-1:
         ###  資料來源類別
        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
        maxPoolSize: 20
    props:
      sql:
        show: true
    config:
      masterslave: # 配置讀寫分離
          # 配置從庫選擇策略,提供輪詢與隨機,這裡選擇用輪詢//random 隨機 //round-robin 輪詢
        load-balance-algorithm-type: round-robin
        name: datasource
      sharding:
        master-slave-rules:
          ds_0:
          ###配置的是主庫的資料庫名,本案例為ds-master-0,其中ds_0為分割槽名。
            master-data-source-name: ds-master-0
          ###配置的是從庫的資料庫名,本案例為ds-master-0-slave-0,ds-master-0-slave-1
            slave-data-source-names: ds-master-0-slave-0,ds-master-0-slave-1
          ds_1:
          ###配置的是主庫的資料庫名,本案例為ds-master-1,其中ds_1為分割槽名。
            master-data-source-name: ds-master-1
          ###配置的是從庫的資料庫名,本案例為ds-master-1-slave-0,ds-master-1-slave-1
            slave-data-source-names: ds-master-1-slave-0,ds-master-1-slave-1
        tables:
          ###需要分表的表名
          t_user:
          ###配置的分表資訊,真實的資料庫資訊。ds_0.t_user_$->{03},表示讀取ds_0資料來源的user_0、user_1、user_2、user_3。
            actual-data-nodes: ds_$->{0..1}.t_user_$->{0..3}
            database-strategy:
              standard:
            ###是配置資料分庫的策略的類,這裡是自定義的類MyDBPreciseShardingAlgorithm
                precise-algorithm-class-name: com.demo.shardingjdbc.MyDBPreciseShardingAlgorithm
           ###配置的資料分表的欄位,是根據id來分的
                sharding-column: id
            table-strategy:
              standard:
          ###是配置資料分表的策略的類,這裡是自定義的類MyTablePreciseShardingAlgorithm
                precise-algorithm-class-name: com.demo.shardingjdbc.MyTablePreciseShardingAlgorithm
          ###配置的資料分表的欄位,是根據id來分的      
                sharding-column: id

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

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

package com.demo.shardingjdbc;


import io.shardingsphere.api.algorithm.sharding.PreciseShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;

import java.util.Collection;

/**
 * 自定義分片演算法
 * 
 * @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 io.shardingsphere.api.algorithm.sharding.PreciseShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;

import java.util.Collection;

/**
 * 自定義分片演算法
 * 
 * @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操作資料庫配置

User.java

package com.demo.shardingjdbc.entity;

import java.io.Serializable;

import lombok.Data;
@Data
public class User implements Serializable {

    private static final long serialVersionUID = -1205226416664488559L;
    private Integer id;
    private String name;
    private String sex;

}

mapper層

package com.demo.shardingjdbc.mapper;


import org.apache.ibatis.annotations.Mapper;

import com.demo.shardingjdbc.entity.User;

import java.util.List;

@Mapper
public interface UserMapper {

    Integer addUser(User user);

    List<User> list();

}

mybatis配置檔案mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="com.demo.shardingjdbc.entity"/>
    </typeAliases>
    <mappers>
        <mapper resource="META-INF/mappers/User.xml"/>
    </mappers>
</configuration>

user.xml

<?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.demo.shardingjdbc.mapper.UserMapper">
    
    <resultMap id="baseResultMap" type="com.demo.shardingjdbc.entity.User">
        <result column="id" property="id" jdbcType="INTEGER" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="sex" property="sex" jdbcType="VARCHAR" />
    </resultMap>
    
    <insert id="addUser" parameterType="com.demo.shardingjdbc.entity.User">
        INSERT INTO t_user (
          id, name, sex
        )
        VALUES (
        #{id,jdbcType=INTEGER},
        #{name,jdbcType=VARCHAR},
        #{sex,jdbcType=VARCHAR}
        )
    </insert>
   
    <select id="list" resultMap="baseResultMap">
        SELECT u.* FROM t_user u order by u.id
    </select>

</mapper>

5、service層

package com.demo.shardingjdbc.service.impl;


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

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

import java.util.List;

@Service
public class UserServiceImpl  implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public Integer addUser(User user) {

        // 強制路由主庫
        return userMapper.addUser(user);
    }

    @Override
    public List<User> list() {

        return userMapper.list();
    }
}

6、controller層

package com.demo.shardingjdbc.controller;


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

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

import lombok.extern.slf4j.Slf4j;

@RestController
@Slf4j
public class UserController {


    @Autowired
    private UserService userService;

    @GetMapping("/users")
    public Object list() {
        return userService.list();
    }

    @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.addUser(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/users,可以查詢資料庫中四個表中的所有資料。可見Sharding-JDBC在插入資料的時候,根據資料分庫分表策略,將資料儲存在不同庫不同表中,查詢時將資料庫從多個表中查詢並聚合。