SpringBoot整合Sharding-JDBC实现水平分表

数据库的水平分表

关于水平分表可以参考文章:https://blog.csdn.net/weixin_38192427/article/details/122441366

需求说明

创建两张表 t_order_1t_order_2,这两张表是订单表水平拆分后的表,通过 Sharding-JDBC 向订单表插入数据, 按照一定的分片规则,主键为偶数的进入 t_order_1,主键为奇数进入 t_order_2,通过 Sharding-JDBC 查询数据,根据 SQL 语句的内容从 t_order_1t_order_2 查询数据

数据库表创建

创建订单库 order_db,然后在 order_db 中创建 t_order_1、t_order_2 表,可以看到两张表的列是完全相同的,这就是水平分表

CREATE TABLE `t_order_1` (
  `order_id` int(11) NOT NULL COMMENT '订单id',
  `price` decimal(10,2) NOT NULL COMMENT '订单价格',
  `user_id` int(11) NOT NULL COMMENT '下单用户id',
  `status` varchar(50) CHARACTER SET utf8mb4 NOT NULL COMMENT '订单状态',
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;


CREATE TABLE `t_order_2` (
  `order_id` int(11) NOT NULL COMMENT '订单id',
  `price` decimal(10,2) NOT NULL COMMENT '订单价格',
  `user_id` int(11) NOT NULL COMMENT '下单用户id',
  `status` varchar(50) CHARACTER SET utf8mb4 NOT NULL COMMENT '订单状态',
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

编写程序

引入 maven 依赖

主要依赖如下,其它依赖自行引入

<dependency>
	<groupId>org.apache.shardingsphere</groupId>
	<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
	<version>4.1.1</version>
</dependency>

实体类

@Data
public class Order implements Serializable {

    @NotNull(message = "参数orderId不能为空")
    private Integer orderId;

    @NotNull(message = "参数price不能为空")
    private BigDecimal price;

    @NotNull(message = "参数userId不能为空")
    private Integer userId;

    @NotBlank(message = "参数status不能为空")
    private String status;
}

dao

Mapper 接口

@Mapper
public interface OrderMapper {

    int insertOrder(Order order);

    List<Order> findOrderByIds(List<Integer> orderIds);
}

Mapper.xml

<insert id="insertOrder" parameterType="org.example.pojo.Order">
	insert into t_order(order_id, price, user_id, status)
	values (#{orderId,jdbcType=INTEGER}, #{price,jdbcType=DECIMAL}, #{userId,jdbcType=INTEGER},
                #{status,jdbcType=VARCHAR})
</insert>


<select id="findOrderByIds" parameterType="java.util.List" resultType="org.example.pojo.Order">
	select
		<include refid="Base_Column_List"></include>
    from t_order AS t
    where t.order_id in
		<foreach collection="list" item="id" open="(" separator="," close=")">
			#{id}
		</foreach>
</select>
  • 注意 SQL 语句的写法,抽象表名是 t_order,并不是具体的 t_order_1t_order_2

Service

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Override
    public int insertOrder(Order order) {
        return orderMapper.insertOrder(order);
    }

    @Override
    public List<Order> getOrderByIds(List<Integer> orderIds) {
        return orderMapper.findOrderByIds(orderIds);
    }
}

Controller

@Controller
@RequestMapping(path = "/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @PostMapping(path = "/addOrder")
    @ResponseBody
    public ResultMap addOrder(@Valid Order order, @NotNull BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            String message = bindingResult.getFieldError().getDefaultMessage();
            return new ResultMap().fail().message(message);
        }
        int i = orderService.insertOrder(order);
        if (i > 0) {
            return new ResultMap().success().message("成功");
        }
        return new ResultMap().fail().message("失败");
    }

    @GetMapping(path = "/getOrder")
    @ResponseBody
    public ResultMap getOrder(@NotNull @RequestBody List<Integer> orderIds) {
        if (orderIds.isEmpty()) {
            return new ResultMap().fail().message("参数orderIds不能为空");
        }
        List<Order> orderList = orderService.getOrderByIds(orderIds);
        if (orderList.isEmpty()) {
            return new ResultMap().fail().message("没有查询到你想要的数据");
        }
        return new ResultMap().success().data(orderList).message("查询成功");
    }
}

application.properties 文件

server.port=8080

# sharding-jdbc分片规则配置开始---------------------------------------------------------------
# 自定义数据源名称为 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://127.0.0.1:3306/order_db?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=UTC
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456
# 指定表的数据分布情况,其中t_order可以自定义,配置数据节点 m1.t_order_1 和 m1.t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=m1.t_order_$->{1..2}
# 指定t_order表的主键是order_id,主键生成策略为SNOWFLAKE,SNOWFLAKE是一种分布式自增算法,保证id全局唯一
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
# order_id为偶数的数据落在t_order_1,为奇数的落在t_order_2,分表策略的表达式为t_order_$->{order_id % 2 + 1}
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2 + 1}
# 打开sql输出日志
spring.shardingsphere.props.sql.show=true
# sharding-jdbc分片规则配置结束---------------------------------------------------------------

# 指定 mapper 文件路径
mybatis.mapper-locations=cldasspath:com/example/mapper/*.xml
mybatis.configuration.cache-enabled=true
# 开启驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true

接口测试

数据插入测试

主键 order_id 为奇数

启动项目,使用 postman 测试接口 http://localhost:8080/order/addOrder,结果如下

在这里插入图片描述
由于传入的参数 orderId1 是奇数,数据应该落在 t_order_2 表中,如下

在这里插入图片描述
再来看看 t_order_1 表中的数据依然是空

在这里插入图片描述

主键 order_id 为偶数

使用 postman 再次测试接口 http://localhost:8080/order/addOrder,结果如下

在这里插入图片描述
由于传入的参数 orderId2 是偶数,数据应该落在 t_order_1 表中,如下

在这里插入图片描述
再来看看 t_order_2 表中的数据依然是上一次插入的数据

在这里插入图片描述

数据查询测试

启动项目,使用 postman 测试接口 http://localhost:8080/order/getOrder,传入的参数 orderIds[1,2] 的数组,进行批量查询,结果如下

在这里插入图片描述
在看看控制台 SQL 日志,如下

在这里插入图片描述

  • 可以看看,SQL 语句分别在 t_order_1t_order_2 表中进行了查询

版权声明:本文为weixin_38192427原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。