经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
SpringBoot3分库分表
来源:cnblogs  作者:知了一笑  时间:2023/8/11 8:35:18  对本文有异议

标签:ShardingSphere5.分库.分表;

一、简介

分库分表的设计和实现方式,在之前的内容中总结过很多,本文基于SpringBoot3ShardingSphere5框架实现数据分库分表的能力;

不得不提ShardingSphere5文档中描述的两个基本概念:

垂直分片

按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用。在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。

水平分片

水平分片又称为横向拆分。 相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。

下面从案例实践中,看看ShardingSphere5框架是如何实现分库分表的原理;

二、工程搭建

1、工程结构

2、依赖管理

这里只看两个核心组件的依赖:shardingsphere-jdbc组件是5.2.1版本,mybatis组件是3.5.13版本,在依赖管理中还涉及MySQL和分页等,并且需要添加很多排除配置,具体见源码;

  1. <!-- Mybatis组件 -->
  2. <dependency>
  3. <groupId>org.mybatis.spring.boot</groupId>
  4. <artifactId>mybatis-spring-boot-starter</artifactId>
  5. <version>${mybatis.version}</version>
  6. </dependency>
  7. <!-- ShardingSphere分库分表 -->
  8. <dependency>
  9. <groupId>org.apache.shardingsphere</groupId>
  10. <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
  11. <version>${shardingsphere.version}</version>
  12. </dependency>

三、配置详解

1、配置文件

此处只展示分库分表的相关配值,默认数据源使用db_master库,注意tb_order库表路由的策略和分片算法的关联关系,其他工程配置详见源码仓库;

  1. spring:
  2. # 分库分表配置
  3. shardingsphere:
  4. datasource:
  5. # 默认数据源
  6. sharding:
  7. default-data-source-name: db_master
  8. names: db_master,db_0,db_1
  9. db_master:
  10. type: com.zaxxer.hikari.HikariDataSource
  11. driver-class-name: com.mysql.cj.jdbc.Driver
  12. jdbc-url: jdbc:mysql://localhost:3306/shard_db
  13. username: root
  14. password: 123456
  15. db_0:
  16. type: com.zaxxer.hikari.HikariDataSource
  17. driver-class-name: com.mysql.cj.jdbc.Driver
  18. jdbc-url: jdbc:mysql://localhost:3306/shard_db_0
  19. username: root
  20. password: 123456
  21. db_1:
  22. type: com.zaxxer.hikari.HikariDataSource
  23. driver-class-name: com.mysql.cj.jdbc.Driver
  24. jdbc-url: jdbc:mysql://localhost:3306/shard_db_1
  25. username: root
  26. password: 123456
  27. rules:
  28. sharding:
  29. tables:
  30. # tb_order逻辑
  31. tb_order:
  32. actual-data-nodes: db_${0..1}.tb_order_${0..2}
  33. # tb_order库路由
  34. database-strategy:
  35. standard:
  36. sharding-column: order_id
  37. sharding-algorithm-name: database_inline
  38. # tb_order表路由
  39. table-strategy:
  40. standard:
  41. sharding-column: order_id
  42. sharding-algorithm-name: table_inline
  43. sharding-algorithms:
  44. # tb_order库路由算法
  45. database_inline:
  46. type: INLINE
  47. props:
  48. algorithm-expression: db_${order_id % 2}
  49. # tb_order表路由算法
  50. table_inline:
  51. type: INLINE
  52. props:
  53. algorithm-expression: tb_order_${order_id % 3}
  54. props:
  55. sql-show: true
  56. sql-comment-parse-enabled: true

2、配置原理

在配置中需要管理三个数据源,shard_db默认库,在操作不涉及需要路由的表时默认使用该数据源,shard_db_0shard_db_1tb_order逻辑表的路由库;

逻辑表tb_order整体使用两个数据库,每个库建3张结构相同相同的表,在操作tb_order数据时,会根据order_id字段值定位数据所属的分片节点;

  • 库路由db_${0..1}采用db_${order_id%2}的算法;
  • 表路由tb_order_${0..2}采用tb_order_${order_id%3}的算法;

四、测试案例

1、主库操作

基于Mybatis持久层框架,实现对shard_db默认库的数据操作,注意控制台的日志打印,可以看到一系列解析逻辑以及库表节点的定位,分页查询使用PageHelper组件即可;

  1. public class MasterTest {
  2. @Autowired
  3. private BuyerMapper buyerMapper ;
  4. @Autowired
  5. private SellerMapper sellerMapper ;
  6. @Test
  7. public void testBuyerQuery (){
  8. // 主键查询
  9. Buyer buyer = buyerMapper.selectByPrimaryKey(1) ;
  10. System.out.println(buyer.getId()+";"+buyer.getBuyerName());
  11. }
  12. @Test
  13. public void testBuyerInsert (){
  14. // 新增数据
  15. Buyer buyer = new Buyer() ;
  16. buyer.setBuyerName("买家Three");
  17. System.out.println(buyerMapper.insert(buyer));
  18. }
  19. @Test
  20. public void testBuyerUpdate (){
  21. // 更新数据
  22. Buyer buyer = buyerMapper.selectByPrimaryKey(3) ;
  23. if (buyer != null){
  24. buyer.setBuyerName("Three买家");
  25. System.out.println(buyerMapper.updateByPrimaryKey(buyer));
  26. }
  27. }
  28. @Test
  29. public void testSellerPage (){
  30. // 1、设置分页和查询条件
  31. PageHelper.startPage(2,2) ;
  32. SellerExample sellerExample = new SellerExample() ;
  33. sellerExample.setOrderByClause("id asc");
  34. // 2、查询数据
  35. List<Seller> sellerList = sellerMapper.selectByExample(sellerExample) ;
  36. // 3、构建分页实体对象
  37. PageInfo<Seller> pageInfo = new PageInfo<>(sellerList) ;
  38. System.out.println(pageInfo);
  39. }
  40. }

2、分库操作

在对tb_order表执行增删改查时,会根据order_id的字段值计算库表的路由节点,注意分页时会查询所有的分库和分表,然后汇总查询的结果;

  1. public class ShardTest {
  2. @Autowired
  3. private OrderMapper orderMapper ;
  4. /**
  5. * 写入100条数据
  6. */
  7. @Test
  8. public void testOrderInsert (){
  9. for (int i=1 ; i<= 100 ; i++){
  10. Order order = new Order(i,i%3+1,i%3+1) ;
  11. // orderMapper.insert(order) ;
  12. }
  13. }
  14. @Test
  15. public void testOrderQuery (){
  16. Order order = orderMapper.selectByPrimaryKey(5) ;
  17. System.out.println(order);
  18. }
  19. @Test
  20. public void testOrderUpdate (){
  21. Order order = orderMapper.selectByPrimaryKey(100) ;
  22. if (order != null){
  23. // 原数据:买家和卖家ID都是2
  24. order.setBuyerId(1);
  25. order.setSellerId(3);
  26. orderMapper.updateByPrimaryKey(order) ;
  27. }
  28. }
  29. @Test
  30. public void testOrderPage (){
  31. // 1、设置分页和查询条件
  32. PageHelper.startPage(1,10) ;
  33. OrderExample orderExample = new OrderExample() ;
  34. orderExample.createCriteria().andBuyerIdEqualTo(2).andSellerIdEqualTo(2);
  35. orderExample.setOrderByClause("order_id desc");
  36. // 2、查询数据
  37. List<Order> orderList = orderMapper.selectByExample(orderExample) ;
  38. // 3、构建分页实体对象
  39. PageInfo<Order> pageInfo = new PageInfo<>(orderList) ;
  40. System.out.println(pageInfo);
  41. }
  42. }

3、综合查询

编写一个订单详情查询接口,同时使用三个库构建数据结构;如果是基于列表数据的检索,比较常规做法的是构建ES索引结构,如果没有搜索的需求,可以在订单表分页查询后去拼接其他结构;

  1. @RestController
  2. public class OrderController {
  3. @Resource
  4. private BuyerMapper buyerMapper ;
  5. @Resource
  6. private SellerMapper sellerMapper ;
  7. @Resource
  8. private OrderMapper orderMapper ;
  9. /**
  10. * 查询订单详情
  11. */
  12. @GetMapping("/order/info/{orderId}")
  13. public Map<String,Object> orderInfo (@PathVariable Integer orderId){
  14. Map<String,Object> orderMap = new HashMap<>() ;
  15. Order order = orderMapper.selectByPrimaryKey(orderId) ;
  16. if (order != null){
  17. orderMap.put("order",order) ;
  18. orderMap.put("buyer",buyerMapper.selectByPrimaryKey(order.getBuyerId())) ;
  19. orderMap.put("seller",sellerMapper.selectByPrimaryKey(order.getSellerId())) ;
  20. }
  21. return orderMap ;
  22. }
  23. }

查看SQL语句

  1. db_master ::: select id, buyer_name from tb_buyer where id = ? ::: [1]
  2. db_master ::: select id, seller_name from tb_seller where id = ? ::: [3]
  3. db_0 ::: select order_id, seller_id, buyer_id from tb_order_1 where order_id = ? ::: [100]

五、参考源码

  1. 文档仓库:
  2. https://gitee.com/cicadasmile/butte-java-note
  3. 源码仓库:
  4. https://gitee.com/cicadasmile/butte-spring-parent

原文链接:https://www.cnblogs.com/cicada-smile/p/17622090.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号