目录
前言需求说明数据库表创建编写程序引入 `maven` 依赖实体类`dao` 层`Mapper` 接口`Mapper.xml``Service` 层`Controller` 层`application.properties` 文件接口测试数据插入测试数据查询测试前言
在 上一篇文章 中我们实现了水平分表,也就是两张列,字段完全相同的表在同一个数据库中,没有完成数据库的水平分割,这篇文章来完成水平方向的分库分表
关于水平分库分表可以参考文章:/weixin_38192427/article/details/122441366
需求说明
水平分库是把同一个表的数据
按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。如order_db_1
和order_db_2
两个数据库,它们分别部署在不同的服务器上,这两个库中的表分别都有t_order_1
和t_order_2
两张表,这两张表的列,字段都是相同的。分别创建数据库,表,完成数据的插入与查询
数据库表创建
分别创建订单库order_db_1
与order_db_2
,然后在order_db_1
与order_db_2
中再分别创建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>
实体类
@Datapublic 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
接口
@Mapperpublic 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 twhere 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
层
@Servicepublic class OrderServiceImpl implements OrderService {@Autowiredprivate OrderMapper orderMapper;@Overridepublic int insertOrder(Order order) {return orderMapper.insertOrder(order);}@Overridepublic List<Order> getOrderByIds(List<Integer> orderIds) {return orderMapper.findOrderByIds(orderIds);}}
Controller
层
@Controller@RequestMapping(path = "/order")public class OrderController {@Autowiredprivate OrderService orderService;@PostMapping(path = "/addOrder")@ResponseBodypublic 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")@ResponseBodypublic 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和m2spring.shardingsphere.datasource.names=m1,m2spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSourcespring.shardingsphere.datasource.m1.driver-class-name=com.mysql.jdbc.Driverspring.shardingsphere.datasource.m1.url=jdbc:mysql://127.0.0.1:3306/order_db_1?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=UTCspring.shardingsphere.datasource.m1.username=rootspring.shardingsphere.datasource.m1.password=123456spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSourcespring.shardingsphere.datasource.m2.driver-class-name=com.mysql.jdbc.Driverspring.shardingsphere.datasource.m2.url=jdbc:mysql://127.0.0.1:3306/order_db_2?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=UTCspring.shardingsphere.datasource.m2.username=rootspring.shardingsphere.datasource.m2.password=123456# 分库策略,以 user_id 为分片键spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column=user_id# 分片策略为 user_id 为偶数操作 m1 数据源,否则操作 m2spring.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_2spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=m$->{1..2}.t_order_$->{1..2}# 指定t_order表的主键是order_id,主键生成策略为SNOWFLAKE,它是一种分布式自增算法,保证id全局唯一spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_idspring.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_2spring.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/*.xmlmybatis.configuration.cache-enabled=true# 开启驼峰命名mybatis.configuration.map-underscore-to-camel-case=true
user_id
:分库策略,以user_id
为分片键m$->{user_id % 2 + 1}
:分片策略表达式,user_id
为偶数操作m1
数据源,否则操作m2
order_id
:分表策略,以order_id
为分片键t_order_$->{order_id % 2 + 1}
:分片策略表达式,order_id
为偶数的数据落在t_order_1
表,为奇数的落在t_order_2
表更多详细的配置文档说明:/document/legacy/3.x/document/cn/manual/sharding-jdbc/configuration/config-spring-boot/
接口测试
数据插入测试
启动项目,使用postman
测试接口http://localhost:8080/order/addOrder
,结果如下
由于传入的参数orderId
和userId
均为奇数,所以数据应该落到数据库order_db_2
中的t_order_2
表中,如下
在看看控制台SQL
日志,如下
再看看数据库order_db_1
中的t_order_2
表数据,依然是空的
参数userId
来确定数据具体要插入到哪个数据库之中参数orderId
来确定数据具体要插入到哪个表之中
数据查询测试
先查看order_db_1
数据库中t_order_1
表的数据如下
再查看order_db_2
数据库中t_order_2
表的数据如下
启动项目,使用postman
测试接口http://localhost:8080/order/getOrder
,传入的参数orderIds
为[1,2]
的数组,进行批量查询,结果如下
在看看控制台SQL
日志,如下
可以看到,这样的SQL
语句出现了2
次,因为总共有4
张表,Sharding-JDBC
会去每一张表中去查询