shardingJdbc–基础–3.1–集成springboot–4版本–水平分表分库,垂直分库,公共表,读写分离

代码位置:https://gitee.com/DanShenGuiZu/learnDemo/tree/master/Sharding-JDBC-learn

1、准备

1.1、 环境搭建

项目版本备注
mysql5.1.47
spring-boot2.5.4
Sharding-JDBC4.0.0-RC1
mybatis-plus2.0.0

1.2、 创建数据库和表

# 创建订单库order_db
CREATE DATABASE `order_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

# 在order_db中创建t_order_1、t_order_2表
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1`  (
  `order_id` bigint(20) NOT NULL COMMENT '订单id',
  `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
  `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
  `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
 
DROP TABLE IF EXISTS `t_order_2`;
CREATE TABLE `t_order_2`  (
  `order_id` bigint(20) NOT NULL COMMENT '订单id',
  `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
  `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
  `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

1.3、代码–水平分表

包含水平分表的配置和功能

1.3.1、代码结构和位置

位置:https://gitee.com/DanShenGuiZu/learnDemo/tree/master/Sharding-JDBC-learn

在这里插入图片描述

1.3.2、maven配置

<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>feizhou</groupId>
    <artifactId>Sharding-JDBC-learn</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Sharding-JDBC-learn</name>
    <description>Sharding-JDBC-learn</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--sharding-jdbc-->

        <dependency>
            <groupId>javax.interceptor</groupId>
            <artifactId>javax.interceptor-api</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>



        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-typehandlers-jsr310</artifactId>
            <version>1.0.2</version>
        </dependency>

        <!--lombok依赖,是为了简化实体类的编写代码量-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

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


</project>

1.3.3、核心代码

OrderDao
@Mapper
@Component
public interface OrderDao {
    /**
     * 新增订单
     * @param price 订单价格
     * @param userId 用户id
     * @param status 订单状态
     * @return
     */
    @Insert("insert into t_order(price,user_id,status) value(#{price},#{userId},#{status})")
    int insertOrder(@Param("price") BigDecimal price, @Param("userId")Long userId,
                    @Param("status")String status);
    /**
     * 根据id列表查询多个订单
     * @param orderIds 订单id列表
     * @return
     */
    @Select({"<script>" +
            "select " +
            " * " +
            " from t_order t" +
            " where t.order_id in " +
            "<foreach collection='orderIds' item='id' open='(' separator=',' close=')'>" +
            " #{id} " +
            "</foreach>"+
            "</script>"})
    List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds);
}

Order
@Data
public class Order implements Serializable {
    private static final long serialVersionUID = 849675519182821942L;
    /**
     * 订单id
     */
    private Long orderId;
    /**
     * 订单价格
     */
    private Double price;
    /**
     * 下单用户id
     */
    private Long userId;
    /**
     * 订单状态
     */
    private String status;


}
application-sharding.properties
#sharding-jdbc 配置
#1.首先定义数据源m1,并对m1进行实际的参数配置。
#2.指定t_order表的数据分布情况,他分布在m1.t_order_1,m1.t_order_2
#3.指定t_order表的主键生成策略为SNOWFLAKE,SNOWFLAKE是一种分布式自增算法,保证id全局唯一
#4.定义t_order分片策略,order_id为偶数的数据落在t_order_1,为奇数的落在t_order_2,分表策略的表达式为t_order_$->{order_id % 2 + 1}

# 1.首先定义数据源m1,并对m1进行实际的参数配置。
spring.shardingsphere.datasource.names = m1
spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver?class?name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://db.hd.com:3306/order_db?useUnicode=true
spring.shardingsphere.datasource.m1.username = xxxx
spring.shardingsphere.datasource.m1.password = xxxx
# 2.指定t_order表的数据分布情况,他分布在m1.t_order_1,m1.t_order_2
spring.shardingsphere.sharding.tables.t_order.actual‐data‐nodes = m1.t_order_$->{1..2}
# 3.指定t_order表的主键生成策略为SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key‐generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key‐generator.type=SNOWFLAKE
# 指定t_order表的分片策略,分片策略包括分片键和分片算法
# 定义t_order分片策略,order_id为偶数的数据落在t_order_1,为奇数的落在t_order_2,分表策略的表达式为t_order_$->{order_id % 2 + 1}
spring.shardingsphere.sharding.tables.t_order.table‐strategy.inline.sharding?column = order_id
spring.shardingsphere.sharding.tables.t_order.table‐strategy.inline.algorithm?expression =t_order_$->{order_id%2 + 1}


# 显示shardingsphere的日志
spring.shardingsphere.props.sql.show = true
MainTests
@SpringBootTest
class MainTests {

    @Resource
    private OrderDao orderDao;
    @Test
    void contextLoads() {
        System.out.println(1111);
    }
    /**
     *
     * 测试水平分表
     * order_id为偶数的数据落在t_order_1表
     * order_id为奇数的数据落在t_order_2表
     */
    @Test
    public void insertOrder(){
        for (int i = 0 ; i<10; i++){
            orderDao.insertOrder(new BigDecimal((i+1)*5),1L,"WAIT_PAY");
        }
    }


    /**
     *  测试水平分表
     *  order_id为偶数,查询t_order_1表
     *  order_id为奇数,查询t_order_2表
     */
    @Test
    public void selectOrderbyIds(){
        List<Long> ids = new ArrayList<>();
        ids.add(373771636085620736L);
        ids.add(373771635804602369L);
        List<Map> maps = orderDao.selectOrderbyIds(ids);
        System.out.println(maps);
    }

}

2、 水平分表测试

order_id为偶数的数据落在t_order_1表
order_id为奇数的数据落在t_order_2表

2.1、插入测试

在这里插入图片描述

在这里插入图片描述

分析

Sharding-JDBC在拿到sql之后干了哪些事儿

  1. 解析sql,获取片键值,在本例中是order_id
  2. Sharding-JDBC通过规则配置 t_order_$->{order_id % 2 + 1},知道了当order_id为偶数时,应该往t_order_1表插数据,为奇数时,往t_order_2插数据。
  3. 于是Sharding-JDBC根据order_id的值改写sql语句,改写后的SQL语句是真实所要执行的SQL语句。
  4. 执行改写后的真实sql语句
  5. 将所有真正执行sql的结果进行汇总合并,返回。

2.2、查询测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3、水平分库

通过分片键,将数据插入order_db_1和order_db_2库中的对应表

3.1、准备

3.1.1、创建库和表

# 创建2个库
CREATE DATABASE `order_db_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE DATABASE `order_db_2` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

# 分别在以上2个库中创建2个表
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`price` decimal(10, 2) NOT NULL COMMENT '订单价格',
`user_id` bigint(20) NOT NULL COMMENT '下单用户id',
`status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `t_order_2`;
CREATE TABLE `t_order_2` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`price` decimal(10, 2) NOT NULL COMMENT '订单价格',
`user_id` bigint(20) NOT NULL COMMENT '下单用户id',
`status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

3.2、了解分片策略

3.2.1、分片策略定义方式

# 分库策略,如何将一个逻辑表映射到多个数据源
spring.shardingsphere.sharding.tables.<逻辑表名称>.database-strategy.<分片策略>.<分片策略属性名>= #分片策略属性值

# 分表策略,如何将一个逻辑表映射为多个实际表
spring.shardingsphere.sharding.tables.<逻辑表名称>.table-strategy.<分片策略>.<分片策略属性名>= #分片策略属性值

3.2.2、Sharding-JDBC自带几种分片策略

3.2.2.1、standard(标准分片策略)

  • 对应类: StandardShardingStrategy
  • 支持操作:提供对 SQL 语句中的=, IN, BETWEEN AND 的分片操作
  • 分片键数量:只支持单分片键
  • 算法/特点:
    • PreciseShardingAlgorithm(必选):处理=, IN 分片
    • RangeShardingAlgorithm(可选):处理BETWEEN AND分片,如果不配置,SQL中的BETWEEN AND将按照全库路由处理。

3.2.2.2、complex(复合分片策略)

  • 对应类:ComplexShardingStrategy
  • 支持操作:提供对 SQL 语句中的=, IN, BETWEEN AND的分片操作
  • 分片键数量:支持多分片键
    • 由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。

3.2.2.3、inline(行表达式分片策略)

  • 对应类:InlineShardingStrategy
  • 支持操作:提供对SQL语句中的 = , IN 的分片操作
  • 分片键数量:只支持单分片键
  • 算法/特点:
    • 使用 Groovy 表达式
    • 适用于简单分片算法
  • 示例:t_user_$->{u_id % 8} 表示根据 u_id 模 8 分成 8 张表(t_user_0 到 t_user_7)

3.2.2.4、hint(Hint 分片策略)

  • 对应类:HintShardingStrategy
  • 算法/特点:
    • 通过 Hint 而非 SQL 解析的方式分片
    • 适用于分片字段非 SQL 决定,而由其他外置条件决定的场景
    • 可通过 Java API 和 SQL 注释(待实现)两种方式使用
  • 示例:内部系统按照员工登录主键分库,而数据库中无此字段

3.2.2.5、none(不分片策略)

  • 对应类:对应 NoneShardingStrategy
  • 不分片的策略

3.3、代码

application-sharding2.properties

创建分片策略配置文件

#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2

spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://zhoufei.db.com:3307/order_db_1?useUnicode=true
spring.shardingsphere.datasource.m1.username = root
spring.shardingsphere.datasource.m1.password = root
spring.shardingsphere.datasource.m2.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m2.url = jdbc:mysql://zhoufei.db.com:3307/order_db_2?useUnicode=true
spring.shardingsphere.datasource.m2.username = root
spring.shardingsphere.datasource.m2.password = root


# 分库策略,以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column = user_id
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression = m$->{user_id % 2 + 1}


# 指定t_order表的数据分布情况,配置数据节点如下
# m1.t_order_1
# m1.t_order_2

# m2.t_order_1
# m2.t_order_2
# 如果这里配置如m1.t_order_$->{1..2},则查询时只会查询m1库的表
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m$->{1..2}.t_order_$->{1..2}

# 指定t_order表的主键生成策略为SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE

# 指定t_order表的分片策略,分片策略包括分片键和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 2 + 1}


# 打开sql输出日志
spring.shardingsphere.props.sql.show = true


OrderDao

package feizhou.business.order;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@Mapper
@Component
public interface OrderDao {
    /**
     * 新增订单
     * @param price 订单价格
     * @param userId 用户id
     * @param status 订单状态
     * @return
     */
    @Insert("insert into t_order(price,user_id,status) value(#{price},#{userId},#{status})")
    int insertOrder(@Param("price") BigDecimal price, @Param("userId")Long userId,
                    @Param("status")String status);
    /**
     * 根据id列表查询多个订单
     * @param orderIds 订单id列表
     * @return
     */
    @Select({"<script>" +
            "select " +
            " * " +
            " from t_order t" +
            " where t.order_id in " +
            "<foreach collection='orderIds' item='id' open='(' separator=',' close=')'>" +
            " #{id} " +
            "</foreach>"+
            "</script>"})
    List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds);


    /**
     * 根据id列表和用户id查询订单
     * @param orderIds
     * @return
     */
    @Select("<script>" +
            "select" +
            " * " +
            " from t_order t " +
            " where t.order_id in " +
            " <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" +
            " #{id} " +
            " </foreach>" +
            " and user_id = #{userId} " +
            "</script>")
    List<Map> selectOrderbyUserAndIds(@Param("userId") Long userId,@Param("orderIds") List<Long> orderIds);
}

MainTests

  /**
     *
     * 分库策略
     * 以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。
     *
     * 分表策略
     * order_id为偶数的数据落在t_order_1表
     * order_id为奇数的数据落在t_order_2表
     */
    @Test
    public void insertOrder2(){
     orderDao.insertOrder(new BigDecimal(1),Long.valueOf(1),"WAIT_PAY");

        for (int i = 0 ; i<10; i++){
            //userId为奇数时插入到sharding_db_2
            orderDao.insertOrder(new BigDecimal((i+1)*5),1L,"WAIT_PAY");
        }
        for (int i = 0 ; i<10; i++){
            ///userId为偶数时插入到sharding_db_1
            orderDao.insertOrder(new BigDecimal((i+1)*10),2L,"WAIT_PAY");
        }
    }
    /**
     *
     * 使用分库分片键查询测试
     *
     * 分库策略
     * 以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。
     *
     * 分表策略
     * order_id为偶数的数据落在t_order_1表
     * order_id为奇数的数据落在t_order_2表
     */
    @Test
    public void selectOrderbyUserAndIds(){

        List<Long> ids = new ArrayList<>();
        ids.add(1037479531180457984L);
        ids.add(1037479530777804801L);

//        //user_id为偶数操作m1数据源,order_id为偶数的数据落在t_order_1表
//        List<Map> maps = orderDao.selectOrderbyUserAndIds(2L,ids);

        //user_id为偶数操作m1数据源,order_id包含奇数和偶数,会查t_order_1、t_order_2表
//        List<Map> maps = orderDao.selectOrderbyUserAndIds(2L,ids);

        //user_id为奇数操作m2数据源,order_id包含奇数和偶数,会查t_order_1、t_order_2表
        List<Map> maps = orderDao.selectOrderbyUserAndIds(1L,ids);

    }

3.4、插入测试


在这里插入图片描述

3.5、查询测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、垂直分库

垂直分库是指按照业务将表进行分类,分布到不同的数据库上面,它的核心理念是专库专用。

4.1、准备

#  创建数据库user_db
CREATE DATABASE `user_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

# 创建表
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `user_id` bigint(20) NOT NULL COMMENT '用户id',
  `fullname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户姓名',
  `user_type` char(1) DEFAULT NULL COMMENT '用户类型',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

4.2、代码

application-sharding3.properties

#数据源,新增m0数据源,对应user_db
spring.shardingsphere.datasource.names = m0,m1,m2
...
spring.shardingsphere.datasource.m0.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver‐class‐name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m0.url = jdbc:mysql://zhoufei.db.com:3307/user_db?useUnicode=true
spring.shardingsphere.datasource.m0.username = root
spring.shardingsphere.datasource.m0.password = root

# t_user分表策略,固定分配至m0的t_user真实表
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes = m$->{0}.t_user
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column = user_id
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression = t_user

UserDao

package feizhou.business.order;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * @ClassName: UserDao
 * @Description 请描述下该类是做什么的
 * @Author feizhou
 * @Date 2025/6/29  19:55
 * @Verson 1.0
 **/
@Mapper
@Component
public interface UserDao {
    /**
     * 新增用户
     * @param userId 用户id
     * @param fullname 用户姓名
     * @return
     */
    @Insert("insert into t_user(user_id, fullname) value(#{userId},#{fullname})")
    int insertUser(@Param("userId")Long userId,@Param("fullname")String fullname);
    /**
     * 根据id列表查询多个用户
     * @param userIds 用户id列表
     * @return
     */
    @Select({"<script>",
            " select",
            " * ",
            " from t_user t ",
            " where t.user_id in",
            "<foreach collection='userIds' item='id' open='(' separator=',' close=')'>",
            "#{id}",
            "</foreach>",
            "</script>"
    })
    List<Map> selectUserbyIds(@Param("userIds")List<Long> userIds);
}

MainTests

    @Test
    public void testInsertUser(){
        for (int i = 0 ; i<10; i++){
            Long id = i + 1L;
            userDao.insertUser(id,"姓名"+ id );
        }
    }
    @Test
    public void testSelectUserbyIds(){
        List<Long> userIds = new ArrayList<>();
        userIds.add(1L);
        userIds.add(2L);
        List<Map> users = userDao.selectUserbyIds(userIds);
        System.out.println(users);
    }

4.3、测试

4.3.1、插入

在这里插入图片描述

在这里插入图片描述

3.3.2、查询

在这里插入图片描述

5、公共表

  • 使用Sharding-JDBC实现公共表。
  • 将公共表在每个数据库都保存一份,所有更新操作都同时发送到所有分库执行。

5.1、特点

  • 数据量较小
  • 变动少
  • 属于高频联合查询的依赖表。
  • 举例:参数表、数据字典表等属于此类型。

5.2、准备

5.2.1、分别在user_db、order_db_1、order_db_2中创建t_dict表

CREATE TABLE `t_dict` (
    `dict_id` bigint(20) NOT NULL COMMENT '字典id',
    `type` varchar(50) NOT NULL COMMENT '字典类型',
    `code` varchar(50) NOT NULL COMMENT '字典编码',
    `value` varchar(50) NOT NULL COMMENT '字典值',
    PRIMARY KEY (`dict_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

5.3、代码

application-sharding4.properties

# 指定t_dict为公共表
spring.shardingsphere.sharding.broadcast‐tables=t_dict

DictDao

package feizhou.business.order;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * @ClassName: DictDao
 **/
@Mapper
@Component
public interface DictDao {
    /**
     * 新增字典
     * @param type 字典类型
     * @param code 字典编码
     * @param value 字典值
     * @return
     */
    @Insert("insert into t_dict(dict_id,type,code,value) value(#{dictId},#{type},#{code},#{value})")
    int insertDict(@Param("dictId") Long dictId,@Param("type") String type, @Param("code")String code, @Param("value")String value);
    /**
     * 删除字典
     * @param dictId 字典id
     * @return
     */
    @Delete("delete from t_dict where dict_id = #{dictId}")
    int deleteDict(@Param("dictId") Long dictId);

    /**
     * 根据id列表查询多个用户
     * @param userIds 用户id列表
     * @return
     */
    @Select({"<script>",
            " select",
            " * ",
            " from t_user t ,t_dict b",
            " where t.user_type = b.code and t.user_id in",
            "<foreach collection='userIds' item='id' open='(' separator=',' close=')'>",
            "#{id}",
            "</foreach>",
            "</script>"
    })
    List<Map> selectUserInfobyIds(@Param("userIds") List<Long> userIds);

}

MainTests

    /**
     *
     * 通过日志可以看出,对t_dict的表的操作会被广播至所有数据源。
     * 插入操作被广播至所有数据源。
     */
    @Test
    public void testInsertDict(){
        //t_dict设置为公共表后,插入数据时会同时插入所有数据源
        dictDao.insertDict(1L,"user_type","1","超级管理员");
        dictDao.insertDict(2L,"user_type","2","二级管理员");
    }

    /**
     *
     * 通过日志可以看出,对t_dict的表的操作会被广播至所有数据源。
     * 删除操作被广播至所有数据源
     */
    @Test
    public void testDeleteDict(){
        //删除公共表同理
        dictDao.deleteDict(2L);
    }

    /**
     *
     * 字典关联查询测试
     * 字典表已在各各分库存在,各业务表即可和字典表关联查询。
     */
    @Test
    public void testSelectUserInfobyIds(){
        List<Long> userIds = new ArrayList<>();
        userIds.add(1L);
        userIds.add(2L);
        List<Map> users = dictDao.selectUserInfobyIds(userIds);

        System.out.println(users.toString());
    }

5.4、测试

5.4.1、对t_dict的表的操作会被广播至所有数据源

在这里插入图片描述

在这里插入图片描述

5.4.2、字典关联查询测试

在这里插入图片描述

6、读写分离

  • Sharding-JDBC读写分离是根据SQL语义的分析,将读操作和写操作分别路由至主库与从库。
  • Sharding-JDBC提供透明化读写分离,让使用方尽量像使用一个数据库一样使用主从数据库集群。

6.1、准备

搭建1主1从数据库,因为这个比较简单,我这就不写了。

  • user_db:主库
  • user_db1:从库

6.2、代码

application-sharding5.properties

# 增加数据源s0,使用上面主从同步配置的从库
spring.shardingsphere.datasource.names = m0,m1,m2,s0
...
spring.shardingsphere.datasource.s0.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.s0.driver‐class‐name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.s0.url = jdbc:mysql://zhoufei.db.com:3307/user_db1?useUnicode=true
spring.shardingsphere.datasource.s0.username = root
spring.shardingsphere.datasource.s0.password = root

# 主库从库逻辑数据源定义ds0为user_db
spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m0
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=s0

# t_user分表策略,固定分配至ds0的t_user真实表
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes = ds0.t_user

6.3、测试

在这里插入图片描述

在这里插入图片描述

更多推荐