Sharding-JDBC:分布式数据库的中间件处理方案

文章标题:

Sharding-JDBC:分布式数据库的中间件解决之道

文章内容

文章目录

  • Sharding-JDBC
    • Sharding-JDBC概览
    • Sharding-JDBC的功用
    • 分库分表的含义
    • 分库分表的类型
    • 分库分表引发的问题
    • 事务一致性难题
    • 跨节点关联查询问题
    • 跨节点分页与排序函数困境
    • 主键重复隐患
    • Sharding-JDBC入门(水平分表)
    • 需求阐述
    • 环境搭建步骤
    • 代码编写流程
    • 流程剖析
    • 其他配置途径
    • 概念术语解读
    • 执行原理剖析
    • 水平分库
    • 执行流程详解
    • 垂直分库(补充)
    • 分片策略配置
    • 用户数据操作

Sharding-JDBC

Sharding-JDBC概览

Sharding-JDBC是由当当网开发的开源分布式数据库中间件,属于轻量级Java框架,在Java的JDBC层提供附加功能。它以客户端直接连接数据库的方式工作,通过jar包提供服务,无需额外部署,可视为增强的JDBC驱动,完全兼容JDBC和多种ORM框架,从3.0版本起,Sharding-JDBC被纳入Sharding-Sphere中。

ShardingSphere是一套开源的分布式数据库中间件解决方案集合,由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(规划中)这三款相互独立的产品构成。它们均提供标准化的数据分片、分布式事务和数据库治理功能,适用于Java同构、异构语言、云原生等多样的应用场景。

在这里插入图片描述

Sharding-JDBC的功用

Sharding-JDBC的核心功能为数据分片读写分离,借助Sharding-JDBC,应用能够透明地通过Jdbc访问已实现分库分表、读写分离的多个数据源,无需关注数据源的数量及数据的分布情况。

  • 适用于任何基于JDBC的ORM框架,如JPA、Hibernate、Mybatis、Spring JDBC Template或直接使用JDBC。
  • 支持任何第三方的数据库连接池,如DBCP、C3P0、BoneCP、Druid、HikariCP等。
  • 支持任意实现JDBC规范的数据库。目前支持MySQL、Oracle、SQLServer、PostgreSQL以及任何遵循SQL92标准的数据库。

官网地址:概览 :: ShardingSphere (apache.org)

在这里插入图片描述

分库分表的含义

随着用户规模的扩大和业务的快速发展,数据库中的数据量急剧增加。然而,关系型数据库自身的单机存储容量、连接数、处理能力有限,会导致系统出现瓶颈,访问性能大幅下降。即便通过增加从库、优化索引等方式,也难以有效解决单表数据量过大带来的性能问题。

解决办法之一是提升服务器硬件能力,但成本较高;另一种办法是将数据分散到不同的数据库中,降低单一数据库的数据量,从而提升性能。例如,将数据库拆分为若干独立的数据库,同时将大表拆分为若干小表,以此缓解性能压力。

分库分表就是为了解决数据量过大导致的数据库性能降低问题,将原本独立的数据库拆分成多个数据库,将大表拆分成多个数据表,使单一数据库、单一数据表的数据量减少,进而提升数据库性能。

分库分表的类型

分库分表包含分库和分表两部分,实际生产中通常有垂直分库、水平分库、垂直分表、水平分表四种方式。

垂直分表:将一个表按字段拆分为多个表,每个表存储部分字段。例如,在商品信息表中,访问频次高的基本信息和访问频次低的详细描述可分别存于不同表,避免IO争抢和锁表,提升热门数据的操作效率。

大字段IO效率低的原因:一是数据量大读取时间长;二是大字段占用空间大,单页存储行数少,IO效率低;三是短字段且高频访问的数据能更快加载到内存,减少磁盘IO,提升性能。锁表是数据库中保证数据一致性和完整性的机制,事务修改表时会锁定该表,阻止其他事务修改,直到事务完成释放锁。

垂直分库:按业务对表分类,分布到不同数据库,各库可部署在不同服务器,实现专库专用。它能解决业务耦合问题,实现业务分级管理等,但未解决单表数据量过大的问题。

水平分库:将同一表的数据按规则拆到不同数据库,各库可在不同服务器。例如,根据类别ID的奇偶性将商品信息分别存储到不同数据库,解决单库大数据、高并发的性能瓶颈,提高系统稳定性和可用性。

水平分表:在同一数据库内,将同一表的数据按规则拆到多个表。与水平分库类似,解决单表数据量大的问题,提升性能和可用性。

分库分表引发的问题

分库分表虽能缓解性能瓶颈,但也带来一些问题。

事务一致性难题

因分库分表将数据分布在不同库甚至服务器,易引发分布式事务问题。

跨节点关联查询问题

分库分表后,商品和文章可能不在同一数据库或服务器,无法直接关联查询。可通过两次查询,先获取关联数据id,再发起第二次请求获取关联数据,最后拼装结果。

跨节点分页、排序函数问题

跨节点多库查询时,limit分页、order by排序等较复杂。需先在各分片节点排序返回,再汇总排序。请求页数越大,性能越差。使用Max、Min等函数时,需先在各分片执行,再汇总计算。

主键重复问题

分库分表后,自增长主键无法保证全局唯一,需设计全局主键避免跨库主键重复。

Sharding-JDBC入门(水平分表)

需求阐述

手动创建两张表mall_order_1mall_order_2,作为订单表拆分后的表。通过Sharding-Jdbc向订单表插入数据,按分片规则,主键为偶数的进入mall_order_1,另一部分进入mall_order_2,并通过Sharding-Jdbc查询数据。

环境搭建
主机名 IP地址
mysql 192.168.8.100/24
[root@mysql ~]# dnf -y install mysql-server mysql
[root@mysql ~]# systemctl start mysqld
[root@mysql ~]# systemctl enable mysqld
[root@mysql ~]# ss -nutlp | grep :3306
[root@mysql ~]# mysqladmin -uroot password "123qqq...A"         #修改root用户密码

创建数据库:tmall_server-mall

mysql> CREATE DATABASE `tmall_server-mall`;

授权root@'%'用户

mysql> CREATE USER root@'%' IDENTIFIED BY '123qqq...A';
mysql> GRANT ALL ON *.* TO root@'%';

tmall_server-mall数据库下创建mall_order_1表和mall_order_2

USE `tmall_server-mall`;
CREATE TABLE mall_order_1
(
    id               BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '数据ID',
    buyer_id         BIGINT UNSIGNED  DEFAULT 0 COMMENT '用户ID',
    buyer_username   VARCHAR(50)      DEFAULT '' COMMENT '用户名',
    order_no         VARCHAR(50)      DEFAULT '' COMMENT '订单编号',
    receiver_name    VARCHAR(32)      DEFAULT '' COMMENT '收货人',
    receiver_phone   VARCHAR(32)      DEFAULT '' COMMENT '收货电话',
    receiver_address VARCHAR(255)     DEFAULT '' COMMENT '收货地址',
    goods_num        INT UNSIGNED     DEFAULT 0 COMMENT '商品数量',
    total_price      DECIMAL(10, 2)   DEFAULT 0 COMMENT '商品销售总价',
    logistics_no     VARCHAR(50)      DEFAULT '' COMMENT '物流单号',
    pay_channel      INT UNSIGNED     DEFAULT 0 COMMENT '支付渠道:1=支付宝,2=微信',
    pay_method       INT UNSIGNED     DEFAULT 0 COMMENT '支付方式:1=在线支付,2=货到付款',
    order_state      TINYINT UNSIGNED DEFAULT 0 COMMENT '订单状态: 0=待支付,1=已支付,待发货, 2=已发货/待收货,3=确认收货/已完成,4=用户关闭,5=平台关闭(商家),6=系统调度关闭',
    gmt_pay          DATETIME         DEFAULT NULL COMMENT '支付时间',
    gmt_create       DATETIME         DEFAULT NULL COMMENT '数据创建时间',
    gmt_modified     DATETIME         DEFAULT NULL COMMENT '数据最后修改时间',
    PRIMARY KEY (id)
) COMMENT '商城-订单' CHARSET = utf8mb4;

CREATE TABLE mall_order_2
(
    id               BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '数据ID',
    buyer_id         BIGINT UNSIGNED  DEFAULT 0 COMMENT '用户ID',
    buyer_username   VARCHAR(50)      DEFAULT '' COMMENT '用户名',
    order_no         VARCHAR(50)      DEFAULT '' COMMENT '订单编号',
    receiver_name    VARCHAR(32)      DEFAULT '' COMMENT '收货人',
    receiver_phone   VARCHAR(32)      DEFAULT '' COMMENT '收货电话',
    receiver_address VARCHAR(255)     DEFAULT '' COMMENT '收货地址',
    goods_num        INT UNSIGNED     DEFAULT 0 COMMENT '商品数量',
    total_price      DECIMAL(10, 2)   DEFAULT 0 COMMENT '商品销售总价',
    logistics_no     VARCHAR(50)      DEFAULT '' COMMENT '物流单号',
    pay_channel      INT UNSIGNED     DEFAULT 0 COMMENT '支付渠道:1=支付宝,2=微信',
    pay_method       INT UNSIGNED     DEFAULT 0 COMMENT '支付方式:1=在线支付,2=货到付款',
    order_state      TINYINT UNSIGNED DEFAULT 0 COMMENT '订单状态: 0=待支付,1=已支付,待发货, 2=已发货/待收货,3=确认收货/已完成,4=用户关闭,5=平台关闭(商家),6=系统调度关闭',
    gmt_pay          DATETIME         DEFAULT NULL COMMENT '支付时间',
    gmt_create       DATETIME         DEFAULT NULL COMMENT '数据创建时间',
    gmt_modified     DATETIME         DEFAULT NULL COMMENT '数据最后修改时间',
    PRIMARY KEY (id)
) COMMENT '商城-订单' CHARSET = utf8mb4;

创建Spring Boot工程

name: spring-boot-sharding-demo

package name: cn.tedu.springboot.sharding.demo

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

使用IDEA连接数据库,用于查看数据库

在这里插入图片描述

引入maven依赖**

        <!--引入sharding-jdbc和Spring Boot整合的Jar包-->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

         <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.16</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

点击右上角m标志,下载依赖,下载完毕之后,查看依赖是否下载成功

在这里插入图片描述
代码编写

分片规则配置

分片规则配置是sharding-jdbc进行分库分表操作的重要依据,包含数据源、主键生成策略、分片策略等配置。在application.properties中配置

创建资源文件:application.properties

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
server.port=9090
spring.application.name =sharding-demo

spring.main.allow-bean-definition-overriding = true
mybatis.configuration.map-underscore-to-camel-case=true


#配置数据源,名字可以自行定义,需要与下方配置保持一致
spring.shardingsphere.datasource.names=m1
#配置druid的连接池
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://192.168.8.100:3306/tmall_server-mall?useUnicode=true
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123qqq...A

#指定mall_order表的数据分布情况,配置数据节点
spring.shardingsphere.sharding.tables.mall_order.actual-data-nodes=m1.mall_order_$->{1..2}
#配置表的主键生成策略,使用雪花算法可以自动解决主键冲突的问题
spring.shardingsphere.sharding.tables.mall_order.key-generator.column=id
spring.shardingsphere.sharding.tables.mall_order.key-generator.type=SNOWFLAKE
#配置表的分片策略,分片策略包含了分片健和分片算法
spring.shardingsphere.sharding.tables.mall_order.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.mall_order.table-strategy.inline.algorithm-expression=mall_order_$->{id % 2 + 1}
#打开SQL输出日志
spring.shardingsphere.props.sql.show=true

通过MyBatis新增数据

创建持久层接口: 在mapper包下创建OrderMapper

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

实现插入功能

package cn.tedu.springboot.sharding.demo.mapper;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface OrderMapper {

//编写新增方法,通过insert注解,指定新增的SQL语句
//当调用insertOrder方法的时候,等于执行上方注解指定的SQL语句
//Param注解

相关文章

暂无评论

暂无评论...