当前位置: 首页 > news >正文

Sharding-JDBC分库分表的基本使用

前言

传统的小型应用通常一个项目一个数据库,单表的数据量在百万以内,对于数据库的操作不会成为系统性能的瓶颈。但是对于互联网应用,单表的数据量动辄上千万、上亿,此时通过数据库优化、索引优化等手段,对数据库操作的性能优化可能无济于事,数据库操作势必称为性能的瓶颈。

究其原因,单机数据库系统的连接数、处理能力等都是有限的。对于这种情况,解决的方案有:

1)提升硬件配置。通过使用更好的CPU、更大的带宽、更大的内存等提升系统的处理能力。但该方案成本较高,而且效果不一定明细;

2)使用商用数据库。商用数据库经过高度优化,性能强大且稳定,提供丰富的管理工具等。但该方案成本较高,而且同样会受到硬件配置的影响;

3)分库分表。将数据分散到不同的数据库;在同一个库中,拆分到多个小的表。从而可以分散到多台硬件设备,减轻单机的压力,提升数据库操作的性能。成本相对较低;

分库分表

分库分表的拆分方式分为垂直拆分和水平拆分。

2.1 分库-垂直拆分

垂直拆分库比较简单,在数据库设计层面就可以实现。可以按照业务模块或实际项目需求,把一个项目中的表拆分到多个数据库中。

如用户维度相关的表放在用户库,业务维度相关的表放在业务库。

这样应用可以根据不同的业务连接不同的数据库,如当前的微服务架构,不同微服务可以使用不同的数据库连接。通过多个数据库分担流量,提高查询速度。

2.2 分表-垂直拆分

垂直拆分表是指把一个大表中的字段拆分成多个表,每个表存储其中一部分字段。

如商品信息表,把基本信息存放在商品表,详情等信息存放在商品详情表,两个表直接通过外键进行关联。商品表访问比较频繁,拆分后,单条记录较小,查询效率较高。而商品详情表,通常在查看单个商品时访问,单条记录较大,但通过主键或其他索引,仍然能够保证效率。

实现相对简单,可以有效的提升查询效率。

2.3 分表-水平拆分

水平拆分表是指把一个表中的数据拆分到多个表中。与垂直拆分表的区别是:垂直拆分表是按列(字段)拆分、水平拆分表是按行(记录)拆分。

如订单表,随着业务规模的提升,订单数据不断的膨胀。可以将订单表按会员、商家、下单时间等进行分表存放。

把一个大表拆分成多个按照一定规律分布的小表,每个表的数据量较小,可以有效的提升数据库操作效率。

2.4 分库-水平拆分

水平拆分库是指把一个表中的数据拆分到多个数据库中,数据库采用分布式部署。在水平拆分表的基础上,如果一个库中的表太多,可以通过水平拆分库,将表数据先分库再进行分表。

如订单表,可以先按商家分库,然后再按会员分表。数据插入时,先按商家,找到匹配的数据库,然后再按会员,找到匹配的表,插入对应数据。

通过水平分库分表,针对分库分表时的指定键的查询时,可以大大的提升查询效率。

分库分表带来的问题

3.1 事务一致性

【源码】SpringBoot事务注册原理-CSDN博客

在上面的博文中分享了何为事务以及单数据库事务在SpringBoot中的实现。对于分库分表,事务的一致性处理将变得更加复杂。在单数据库中,事务原子性、隔离性是由数据库来保证,但在多数据库中,事务的特性中只有持久性能够由数据库保证,其他都需要由程序开发者自行实现。

3.2 跨库跨表查询

对于单库单表,无论是关联查询,还是分页、排序,都是在一张表中通过一条SQL即可实现。而进行分表分库之后,数据分布在不同的库、不同的表,实现变得比较复杂。最坏的情况是需要先在不同的库、不同的表中查询数据,进行排序并返回,然后程序中汇总再获取满足条件的数据。

3.3 主键重复

在单库单表中,可以通过数据库提供的自增长设置主键,但在分库分表中,自增长的主键会存在重复。因此需要使用全局唯一的主键。如UUID、雪花算法等。

3.4 公共表

对于一些字典、配置类等数据量较小、变动少,而且需要高频联合查询的表,可以建立公共表。在分库环境中,每个库都保存一份相同的公共表。

Sharding-JDBC介绍

针对分库分表带来的问题,通过Sharding-JDBC这个框架,都可以有效的解决。

Sharding-JDBC 是一款由当当网开源的分库分表中间件,它可以透明地为 Java 应用程序提供数据库分片功能,无需关心底层的数据库分片细节。它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名为 ShardingSphere,2020年4⽉16⽇正式成为 Apache 软件基⾦会的顶级项⽬。

ShardingSphere官网:Apache ShardingSphere

Sharding-JDBC入门

以下以订单分表为例,介绍Sharding-JDBC的基本使用。

1)订单表:订单表的字段有订单id、会员id、总价格、状态、下单时间;

2)创建两个订单表,分表为tb_order_1和tb_order_2;

3)分表规则:以订单id分表,id被2整除的放tb_order_1,不能被2整除的放tb_order_2;

5.1 导入sharding-jdbc-spring-boot-starter依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.4</version><relativePath/> <!-- lookup parent from repository --></parent><modelVersion>4.0.0</modelVersion><artifactId>Sharing-JDBC-demo</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.6</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version><scope>compile</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional><scope>runtime</scope></dependency></dependencies></project>

引入sharding-jdbc-spring-boot-starter,此处的数据库连接池采用Druid。需要注意的是,不能直接使用druid-spring-boot-starter,否则启动会报错,因为该starter会自动注入SqlSessionFactory和SqlSessionTemplate,和Sharding-JDBC冲突。

5.2 sharding-jdbc配置

# 单数据库,inline分片策略测试
server:port: 8080#sharding-jdbc分片规则配置
spring:shardingsphere:datasource:names: order1 #数据源名称,有几个数据源就写几个名字,和url中的数据库名字保持一致order1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/shardingjdbctest?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=falseusername: rootpassword: 123456#分表策略#按照id分表,id使用雪花算保证全局唯一,具体算法:tb_order是表前缀,拼接上:$->{id % 2}  的值sharding:tables:tb_order: #逻辑表actual-data-nodes: order1.tb_order_$->{1..2}  #order1:数据源名称;两个tb_order表,分别为tb_order_1和tb_order_2key-generator: # 指定主键生成策略column: order_idtype: SNOWFLAKEtable-strategy:   #分表策略inline:sharding-column: order_id   #分片键。对id进行分表algorithm-expression: tb_order_$->{order_id % 2 + 1}  #分片算法props:sql:show: true  # 是否打印sql

1)所有sharding-jdbc的相关配置都在spring.shardingsphere开头的属性中;

2)数据源的配置在spring.shardingsphere.datasource开头的属性中;

3)分库分表策略的配置在spring.shardingsphere.sharding.tables开头的属性中;

分库分表策略都是针对表进行的。先指定逻辑表,然后指定分库策略、分表策略等。

5.3 实体类

package com.jingai.sharing.jdbc.entity;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;import java.util.Date;@Data
@ToString
@TableName("tb_order")
public class OrderEntity {private long orderId;private long memberId;private float totalPrice;private String status;private Date orderTime;}

在实体类中,@TableName指定配置中的逻辑表。

5.4 Mapper类

package com.jingai.sharing.jdbc.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jingai.sharing.jdbc.entity.OrderEntity;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;public interface OrderMapper extends BaseMapper<OrderEntity> {@Insert("insert into tb_order(member_id, total_price, status, order_time) values " +"(#{memberId}, #{totalPrice}, #{status}, #{orderTime})")@Options(useGeneratedKeys = true, keyProperty = "orderId")int insert2(OrderEntity order);
}

在5.2的配置中,通过key-generator设置了逻辑表的主键生成策略为雪花算法。当进行数据插入时,需要编写新的插入接口,不能直接使用Mybatis-plus中的insert()接口。因为在默认的insert()接口中,实体对象的orderId为0,不会走配置的雪花算法。

5.5 Service类

package com.jingai.sharing.jdbc.service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jingai.sharing.jdbc.dao.OrderMapper;
import com.jingai.sharing.jdbc.entity.OrderEntity;
import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service
public class OrderService extends ServiceImpl<OrderMapper, OrderEntity> {@Resourceprivate OrderMapper orderMapper;public long insert2(OrderEntity order) {int rs = orderMapper.insert2(order);return rs > 0 ? order.getOrderId() : 0;}}

为了便于测试,此处省略了Service的接口类。

5.6 Controller类

@RestController
public class OrderController {@Resourceprivate OrderService orderService;@RequestMapping("order")public String order(OrderEntity order) {order.setOrderTime(new Date());long insert = orderService.insert2(order);return insert > 0 ? "success" : "fail";}}

访问以上的order接口,系统打印的日志如下:

插入的数据为:

结合日志,执行流程如下:

1)在插入之前,解析逻辑SQL,获取分片键值tb_order;

2)配置的分库分表规则为以order_id作为分表的键,id被2整除的放tb_order_1,不能被2整除的放tb_order_2,以上的order_id为1014578121078210560,所以实际存放的表为tb_order_1;

3)根据实际操作的表tb_order_1,修改SQL语句;

4)执行真实SQL语句;

结尾

限于篇幅,本篇先分享到这里。

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

相关文章:

Sharding-JDBC分库分表的基本使用

前言 传统的小型应用通常一个项目一个数据库&#xff0c;单表的数据量在百万以内&#xff0c;对于数据库的操作不会成为系统性能的瓶颈。但是对于互联网应用&#xff0c;单表的数据量动辄上千万、上亿&#xff0c;此时通过数据库优化、索引优化等手段&#xff0c;对数据库操作…...

7月信用卡新规下:信用卡欠的钱不用还了?

说到信用卡&#xff0c;现在基本上人手一张&#xff0c;大家都有使用过。但你知道吗&#xff0c;使用信用卡不是这么简单容易的事&#xff0c;比如会对你的贷款有影响&#xff0c;透支不还逾期对生活的影响&#xff0c;信用卡新规对持卡人和银行那边的影响。 一、只要不逾期&am…...

坑——python的redis库的decode_responses设置

python的redis库查询返回的值默认是返回字节串&#xff0c;可以在redis.Redis()方法中通过设置decode_responses参数&#xff0c;让返回值直接是字符串&#xff1b; 查询返回字节串是因为Redis()方法中decode_responses默认值是False&#xff1a; 设置decode_responses为True就…...

从项目中学习Bus-Off的快慢恢复

0 前言 说到Bus-Off&#xff0c;大家应该都不陌生&#xff0c;使用VH6501干扰仪进行测试的文章在网上数不胜数&#xff0c;但是一般大家都是教怎么去干扰&#xff0c;但是说如何去看快慢恢复以及对快慢恢复做出解释比较少&#xff0c;因此本文以实践的视角来讲解Bus-Off的快慢恢…...

视频参考帧和重构帧复用

1、 视频编码中的参考帧和重构帧 从下图的编码框架可以看出&#xff0c;每编码一帧需要先使用当前帧CU(n)减去当前帧的参考帧CU&#xff08;n&#xff09;得到残差。同时&#xff0c;需要将当前帧的重构帧CU*&#xff08;n&#xff09;输出&#xff0c;然后再读取重构帧进行预测…...

js修改scss变量

style.scss $color : var(--color,#ccc); // 默认值 #ccc .color{background: $color; } 定义了一个scss变量&#xff08;$color&#xff09;&#xff0c;用普通的css变量&#xff08;--color&#xff09;给他赋值&#xff0c;这里需要一个默认值&#xff0c;此时css变量(--co…...

【中霖教育怎么样】报考注册会计师有年龄限制吗?

【中霖教育怎么样】报考注册会计师有年龄限制吗? 申请参加注册会计师考试有没有年龄约束? 对于注册会计师的考试&#xff0c;不存在具体的年龄上限。而且该考试的入学门栏相对低&#xff0c;主要对考生的年龄下限规定。 在专业阶段&#xff0c;注册会计师考试要求考生具备…...

PHP验证日本手机电话号码

首先&#xff0c;您需要了解手机号码的规格。 根据 &#xff0c;手机和PHS&#xff08;个人手持电话系统&#xff09;可以理解为以“070”、“080”和“090”开头的11位数字。 此外&#xff0c;以“050”开头的11位特定IP电话号码也将包含在该目标中。 关于以“060”开头的F…...

Qt 配置ASan

Qt 配置ASan 文章目录 Qt 配置ASan摘要关于ASan&#xff08;AddressSanitizer&#xff09;在Qt中配置 ASan1. 安装必要的工具2. 修改项目的 .pro 文件3. 重新构建项目4. 运行应用程序5. 分析错误报告示例注意事项 关键字&#xff1a; Qt、 ASan、 AddressSanitizer 、 GCC …...

MySQL常用操作命令大全

文章目录 一、连接与断开数据库1.1 连接数据库1.2 选择数据库1.3 断开数据库 二、数据库操作2.1 创建数据库2.2 查看数据库列表2.3 删除数据库 三、表操作3.1 创建表3.2 查看表结构3.3 修改表结构3.3.1 添加列3.3.2 删除列3.3.3 修改列数据类型 3.4 删除表 四、数据操作4.1 插入…...

有人物联的串口服务器USR-TCP232-410S基本测试通信和使用方案(485串口和232串口)

1.将 410S(USR-TCP232-410S&#xff0c;简称 410S 下同)的串口通过串口线(或USB 转串口线)与计算机相连接&#xff0c;通过网线将 410S 的网口 PC 的网口相连接&#xff0c;检测硬件连接无错误后&#xff0c;接入我们配送的电源适配器&#xff0c;给 410S 供电。观察指示灯状态…...

二维码登录的原理

二维码登录的原理: 二维码登录是一种基于移动设备和网络技术的便捷登录方式。其原理主要依赖于以下几个关键要素: 随机生成:服务器端随机生成一个具有唯一性和时效性的二维码。编码信息:这个二维码包含了特定的登录信息,例如用户标识、会话标识、时间戳等。扫描识别:用户…...

归并排序详解(递归与非递归)

归并排序是建立在归并操作上的一种有效算法。该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列有序&#xff0c;再使子序列间断有序。若将两个有序表合并成一个有序表&#xff0c;成为二路归并。 一…...

计算机系统基础(二)

1.数值数据的表示 为什么采用二进制&#xff1f; 二进制只有两种基本状态&#xff0c;两个物理器件就可以表示0和1二进制的编码、技术、运算规则都很简单0和1与逻辑命题的真假对应&#xff0c;方便通过逻辑门电路实现算术运算 数值数据表示的三要素 进位记数制&#xff08;十…...

vue根据文字长短展示跑马灯效果

介绍 为大家介绍一个我编写的vue组件 auto-marquee &#xff0c;他可以根据要展示文本是否超出展示区域&#xff0c;来判断是否使用跑马灯效果&#xff0c;效果图如下所示 假设要展示区域的宽度为500px&#xff0c;当要展示文本的长度小于500px时&#xff0c;只会展示文本&…...

leetcode-21-回溯-全排列及其去重

一、[46]全排列 给定一个 没有重复 数字的序列&#xff0c;返回其所有可能的全排列。 示例: 输入: [1,2,3]输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 其中&#xff0c;不需要使用startIndex used数组&#xff0c;其实就是记录此时path里都有哪些元素…...

如何根据两个关键字查询报错日志的位置

1、查找两个关键字&#xff08;无顺序要求&#xff09; 如果你不关心这两个关键字出现的顺序&#xff0c;你可以使用egrep&#xff08;等同于grep -E&#xff09;或grep的-E选项来启用扩展正则表达式&#xff0c;并使用管道&#xff08;|&#xff09;来组合两个搜索模式。 gr…...

短视频预算表:成都柏煜文化传媒有限公司

短视频预算表&#xff1a;精打细算&#xff0c;打造高质量视觉盛宴 在数字时代&#xff0c;短视频以其独特的魅力迅速占领了互联网内容的半壁江山&#xff0c;成为品牌宣传、文化传播乃至个人表达的重要载体。然而&#xff0c;每一个成功的短视频背后&#xff0c;都离不开一份…...

【Llama 2的使用方法】

Llama 2是Meta AI&#xff08;Facebook的母公司Meta的AI部门&#xff09;开发并开源的大型语言模型系列之一。Llama 2是在其前身Llama模型的基础上进行改进和扩展的&#xff0c;旨在提供更强大的自然语言处理能力和更广泛的应用场景。 以下是Llama 2的一些关键特性和更新点&am…...

mysql-sql-第十三周

学习目标&#xff1a; sql 学习内容&#xff1a; 37.查询各科成绩最高分、最低分和平均分&#xff1a; 以如下形式显示&#xff1a;课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率 及格为>60,中等为&#xff1a;70-80,优良为&#xff1a;80-90,优秀…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...