目录
数据库的水平分表
关于水平分表可以参考文章:https://blog.csdn.net/weixin_38192427/article/details/122441366
需求说明
创建两张表 t_order_1 和 t_order_2,这两张表是订单表水平拆分后的表,通过 Sharding-JDBC 向订单表插入数据, 按照一定的分片规则,主键为偶数的进入 t_order_1,主键为奇数进入 t_order_2,通过 Sharding-JDBC 查询数据,根据 SQL 语句的内容从 t_order_1 或 t_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_1或t_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,结果如下

由于传入的参数 orderId 为 1 是奇数,数据应该落在 t_order_2 表中,如下

再来看看 t_order_1 表中的数据依然是空

主键 order_id 为偶数
使用 postman 再次测试接口 http://localhost:8080/order/addOrder,结果如下

由于传入的参数 orderId 为 2 是偶数,数据应该落在 t_order_1 表中,如下

再来看看 t_order_2 表中的数据依然是上一次插入的数据

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

在看看控制台 SQL 日志,如下

- 可以看看,
SQL语句分别在t_order_1和t_order_2表中进行了查询
版权声明:本文为weixin_38192427原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。