• sharding-jdbc分库分表(一)


    以商城商品为例

    垂直分表:将一个表按照字段分成多表,每个表存储其中一部分字段

    它带来的提升是:

    1、为了避免IO争抢并减少锁表的几率,查看详情的用户与商品信息浏览相互不影响

    2、充分发挥热门数据的操作效率,商品信息的操作的高效率不会被商品描述的低效率所拖累

    垂直分库:

    垂直分库是指按照业务将表进行分类,分页到不同的数据库上面,每个库可以放在不同的服务器上,它的核心理念是专库专用

    它带来的提升是:

    1、解决业务层面的耦合,业务清晰

    2、能对不同业务的数据进行分组管理,维护,监控,扩展等

    3、高并发场景下,垂直分库一定程度的提升IO,数据库连接数,降低单机硬件资源的瓶颈

    垂直分库通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,但是依然没有解决单表数据量过大的问题。

    水平分库:

    是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。

    它带来的提升是:

    1、解决了单库大数据,高并发的性能瓶颈

    2、提高了系统的稳定性及可用性。稳定性体现在IO冲突少,锁定减少,可用性指某个库出问题,部分数据可用 

    水平分表:

    水平分表是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中

    它带来的提升是:

    1、优化单一表数据量过大而产生的性能问题

    2、避免IO争抢并减少锁表的几率

    分库分表带来的问题:

    1、事务一致性问题

            由于分库分表把数据分页在不同库甚至不同服务器,不可避免分带来分页式事务问题

    2、跨节点关联查询

    3、跨节点分页、排序、函数

    4、主键重复问题

    在分库分表环境中,由于表中数据同时存在不同的数据库中,主键值平时使用的自增长 将无用武之地,某个分区数据库生成的ID无法保证全局唯一。因此需要单独设计全局主键,以避免跨库主键重复问题

    5、公共表

    实际的应用场景中,参数表,数据字典表等都是数据量较少,变动少,而且属于高频联合查询的依赖表。

    可以将这类表在每个数据库都保存一份,所有对公共表的更新操作都同时发送到所有分库执行

    由于分库分表之后,数据被分散在不同的数据库、服务器。因此,对数据的操作也就无法通过常规方式完成,并且它还带来了一系列的问题。

    Sharding-jdbc介绍

    sharding-jdbc是当当网研发的开源分页式数据库中间件,从3.0开始Sharding-jdbc被包含在Sharding-Sphere,之后该项目进入 Apache,4.0版本之后的版本为Apache版本

    Sharding-jdbc它定位为级Java框架,在java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

    Sharding-jdbc的核心功能为数据分片和读写分离,通过Sharding-JDBC,应用可以透明的使用jdbc访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分页。

    与jdbc性能对比:

    1、性能损耗测试:服务器资源充足、并发数相同,比较JDBC和Sharding-JDBC性能损耗,sharding-jdbc相对JDBC损耗不超过7%

    2、性能对比测试:服务器资源使用到极限,相同场景JDBC与sharding-jdbc的吞吐量相当

    3、性能对比测试:服务器资源使用到极限,sharding-jdbc采用分库分表后,sharding-jdbc吞吐量较JDBC不分表有接近2倍提升

    sharding-jdbc快速入门

    使用sharding-jdbc完成对订单表的水平分表,通过快速入门程序的开发,快速体验sharding-jdbc的使用方法。

    人工创建两张表,t_order_1和t_order_2,这两张表是订单表拆分后的表,通过sharding-jdbc向订单表插入数据,按照一定的分片规则,主键为偶数的进入t_order_1,另一部分数据进入t_order_2,通过sharding-jdbc查询数据,根据SQL语句的内容从t_order_1或t_order_2查询数据。

    代码mode(水平分表):

    配置yml

    1. server:
    2. port: 8082
    3. servlet:
    4. context-path: /sharding-jdbc-simple-demo
    5. spring:
    6. application:
    7. name: sharding-jdbc-simple-demo
    8. http:
    9. encoding:
    10. enabled: true
    11. charset: UTF-8
    12. force: true
    13. #shrading-jdbc配置
    14. shardingsphere:
    15. datasource:
    16. names: m1
    17. m1:
    18. type: com.alibaba.druid.pool.DruidDataSource
    19. driver-class-name: com.mysql.jdbc.Driver
    20. url: jdbc:mysql://localhost:3306/shareding?useUnicode=true
    21. username: root
    22. password: 123456
    23. sharding: #指定t_order表的数据分页情况,配置数据节点 m1.t_order_1 m1.t_order_2
    24. tables:
    25. t_order:
    26. actual-data-nodes: m1.t_order_$->{1..2}
    27. key-generator:
    28. column: id #主键字段
    29. type: SNOWFLAKE #指定t_order表主键生成策略
    30. table-strategy: #指定t_order表的分片策略,分片策略包括分片键和分片算法
    31. inline:
    32. sharding-column: id #分片键
    33. algorithm-expression: t_order_$->{id%2+1} #分片算法
    34. props:
    35. sql:
    36. show: true #输出sharding-jdbc的真实sql
    37. mybatis:
    38. configuration:
    39. map-underscore-to-camel-case: true
    40. swagger:
    41. enable: true
    42. logging:
    43. level:
    44. root: info
    45. org:
    46. springframeword:
    47. web: info
    48. cn:
    49. ping: debug
    50. druid:
    51. sql: debug

    maven:

    1. "1.0" encoding="UTF-8"?>
    2. "http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. org.springframework.boot
    6. spring-boot-starter-parent
    7. 2.0.3.RELEASE
    8. 4.0.0
    9. sharding-jdbc-simple
    10. org.springframework.boot
    11. spring-boot-starter-web
    12. com.alibaba
    13. druid-spring-boot-starter
    14. 1.2.11
    15. mysql
    16. mysql-connector-java
    17. 5.1.46
    18. com.baomidou
    19. mybatis-plus-boot-starter
    20. 3.5.1
    21. org.apache.shardingsphere
    22. sharding-jdbc-spring-boot-starter
    23. 4.0.0-RC1
    24. org.projectlombok
    25. lombok
    26. io.springfox
    27. springfox-swagger-ui
    28. 2.8.0
    29. org.springframework.boot
    30. spring-boot-starter-test

    mysql创建表:

    1. CREATE TABLE `t_order_1` (
    2. `id` bigint(20) NOT NULL COMMENT '订单id',
    3. `price` decimal(10,2) NOT NULL COMMENT '订单价格',
    4. `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
    5. `status` varchar(50) NOT NULL COMMENT '订单状态',
    6. PRIMARY KEY (`id`) USING BTREE
    7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    8. CREATE TABLE `t_order_2` (
    9. `id` bigint(20) NOT NULL COMMENT '订单id',
    10. `price` decimal(10,2) NOT NULL COMMENT '订单价格',
    11. `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
    12. `status` varchar(50) NOT NULL COMMENT '订单状态',
    13. PRIMARY KEY (`id`) USING BTREE
    14. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    实体类:

    1. package cn.ping.entity;
    2. import com.baomidou.mybatisplus.annotation.TableName;
    3. import lombok.Builder;
    4. import lombok.Data;
    5. import java.math.BigDecimal;
    6. /**
    7. * @author: yejianping
    8. * @date: 2022/12/5 15:12:25
    9. * @email: 1152665905@qq.com
    10. * @Description:
    11. */
    12. @Data
    13. @Builder
    14. @TableName("t_order")
    15. public class Order {
    16. private Long id;
    17. private BigDecimal price;
    18. private Long userId;
    19. private String status;
    20. }

    mapper类:

    1. package cn.ping.mapper;
    2. import cn.ping.entity.Order;
    3. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    4. import org.apache.ibatis.annotations.Param;
    5. import org.apache.ibatis.annotations.Select;
    6. import java.util.List;
    7. /**
    8. * @author: yejianping
    9. * @date: 2022/12/5 15:14:17
    10. * @email: 1152665905@qq.com
    11. * @Description:
    12. */
    13. public interface OrderMapper extends BaseMapper {
    14. List selectOrderList(@Param("position") Integer startPosition, @Param("size")Integer size);
    15. }

    mapper.xml

    1. "1.0" encoding="UTF-8"?>
    2. "-//mybatis.org//DTD Mapper 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    4. "cn.ping.mapper.OrderMapper">

    service

    1. package cn.ping.server;
    2. import cn.ping.entity.Order;
    3. import com.baomidou.mybatisplus.core.metadata.IPage;
    4. import com.baomidou.mybatisplus.extension.service.IService;
    5. import java.util.List;
    6. /**
    7. * @author: yejianping
    8. * @date: 2022/12/5 15:16:52
    9. * @email: 1152665905@qq.com
    10. * @Description:
    11. */
    12. public interface IOrderService extends IService {
    13. /**
    14. * 通过ids查询Order
    15. * @param ids
    16. * @return
    17. */
    18. List getOrderByIds(List ids);
    19. IPage getOrderPage(Integer page,Integer size);
    20. List getOrderList(Integer page,Integer size);
    21. }

    serviceImpl

    1. package cn.ping.server.impl;
    2. import cn.ping.entity.Order;
    3. import cn.ping.mapper.OrderMapper;
    4. import cn.ping.server.IOrderService;
    5. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    6. import com.baomidou.mybatisplus.core.metadata.IPage;
    7. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    8. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    9. import lombok.extern.slf4j.Slf4j;
    10. import org.springframework.stereotype.Service;
    11. import org.springframework.util.CollectionUtils;
    12. import java.util.List;
    13. /**
    14. * @author: yejianping
    15. * @date: 2022/12/5 15:21:06
    16. * @email: 1152665905@qq.com
    17. * @Description:
    18. */
    19. @Service
    20. @Slf4j
    21. public class OrderServiceImpl extends ServiceImpl implements IOrderService {
    22. @Override
    23. public List getOrderByIds(List ids) {
    24. if(CollectionUtils.isEmpty(ids)){
    25. return null;
    26. }
    27. return this.listByIds(ids);
    28. }
    29. @Override
    30. public IPage getOrderPage(Integer page, Integer size) {
    31. LambdaQueryWrapper lqw = new LambdaQueryWrapper();
    32. lqw.orderByDesc(Order::getPrice);
    33. return page(new Page<>(page,size),lqw);
    34. }
    35. @Override
    36. public List getOrderList(Integer page,Integer size){
    37. return this.baseMapper.selectOrderList((page-1)*size,size);
    38. }
    39. }

    测试类

    1. package cn.ping;
    2. import cn.ping.entity.Dog;
    3. import cn.ping.entity.Order;
    4. import cn.ping.server.IDogService;
    5. import cn.ping.server.IOrderService;
    6. import com.baomidou.mybatisplus.core.metadata.IPage;
    7. import lombok.extern.slf4j.Slf4j;
    8. import net.bytebuddy.asm.Advice;
    9. import org.junit.Test;
    10. import org.junit.runner.RunWith;
    11. import org.springframework.beans.factory.annotation.Autowired;
    12. import org.springframework.boot.test.context.SpringBootTest;
    13. import org.springframework.test.context.junit4.SpringRunner;
    14. import java.math.BigDecimal;
    15. import java.util.ArrayList;
    16. import java.util.Arrays;
    17. import java.util.List;
    18. import java.util.Random;
    19. /**
    20. * @author: yejianping
    21. * @date: 2022/12/5 15:22:35
    22. * @email: 1152665905@qq.com
    23. * @Description:
    24. */
    25. @RunWith(SpringRunner.class)
    26. @SpringBootTest(classes = {ShardingJdbcSimpleApplication.class})
    27. @Slf4j
    28. public class OrderTest {
    29. @Autowired
    30. private IOrderService orderService;
    31. @Autowired
    32. private IDogService dogService;
    33. @Test
    34. public void testOrderInsert(){
    35. List orderList = new ArrayList<>();
    36. for (int i = 0; i < 20; i++) {
    37. Order order = Order.builder()
    38. .price(new BigDecimal(new Random().nextInt(100)))
    39. .status("SUCCESS")
    40. .userId(1L)
    41. .build();
    42. orderList.add(order);
    43. }
    44. orderService.saveBatch(orderList);
    45. /*Order order = Order.builder()
    46. .price(new BigDecimal(10))
    47. .status("SUCCESS")
    48. .userId(1L)
    49. .build();
    50. orderService.save(order);*/
    51. }
    52. @Test
    53. public void testFindByIds(){
    54. Long[] ids = {1599673041937334275L,1599673040175726594L};
    55. List orderByIds = orderService.getOrderByIds(Arrays.asList(ids));
    56. for (Order order : orderByIds) {
    57. log.info(order.toString());
    58. }
    59. }
    60. @Test
    61. public void testOrderPage(){
    62. IPage orderPage = orderService.getOrderPage(1, 10);
    63. for (Order order : orderPage.getRecords()) {
    64. log.info(order.toString());
    65. }
    66. }
    67. @Test
    68. public void testOrderList(){
    69. List orderList = orderService.getOrderList(1, 10);
    70. for (Order order : orderList) {
    71. log.info(order.toString());
    72. }
    73. }
    74. }

    sharding-jdbc和mybatis plus分页冲突,不能使用分页插件,查询总数有问题

  • 相关阅读:
    在外远程访问禅道,点亮软件测试新技能「内网穿透」
    数据结构——新建一棵完全二叉树(C语言动态实现)
    TC8:UDP_USER_INTERFACE_01-08
    12_C++_链表_回调函数
    Java中生成一个唯一的文件名的方法
    iOS 配置通用链接(Universal Link)服务端和开发者后台都配置好了,还是跳转不到App
    虚拟机桥接模式无法联网
    视频播放速度调节的chrome插件,怎么快捷键调节B站播放速度
    北京筑龙:快消品行业如何迈入采购数字化快车道?
    集合框架的认识(四)Map
  • 原文地址:https://blog.csdn.net/qq_20768305/article/details/128171379