关于《ShardingJDBC》的分库分表整理

417 阅读4分钟

1.什么是sharingJDBC。

ShardingSphere

​ 1.sharding-jdbc是ShardingSphere的其中一个模块,摘抄官网一段简介:

(官方中文文档:shardingsphere.apache.org/document/cu…

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

ShardingSphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。 它与NoSQL和NewSQL是并存而非互斥的关系。NoSQL和NewSQL作为新技术探索的前沿,放眼未来,拥抱变化,是非常值得推荐的。反之,也可以用另一种思路看待问题,放眼未来,关注不变的东西,进而抓住事物本质。 关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。

sharding-JDBC

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

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

2.使用sharingJDBC

准备工作

创建java maven 项目工程 引入sharding-JDBC 坐标

<dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>

垂直分表

垂直分表概念:垂直分表体现在设计数据库时,“数据库第二范式” 保证每列都是不可在分的最小单元。将常用的字段罗列到一张表内,不常用的字段、与其关联的字段,放入另一张表中。

垂直分库

垂直分库:根据业务将数据库分布在不同的服务器上,专库专用。针对业务使用数据库

数据库

image-20220405143924129

垂直分库中 库中只存放关于 ‘订单’ 的信息。

properties 配置 (多数据源)

# sharingJDBC 垂直分表 专库专表
spring.shardingsphere.datasource.names=m1,m2

# 一个实体类对应两张表 覆盖
spring.main.allow-bean-definition-overriding=true

# m1数据源基础配置
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/order_1?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=xxxxx

# m2数据源基础配置
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://localhost:3306/order_2?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=xxxxx

# 专库专表
spring.shardingsphere.sharding.tables.order_info.actual-data-nodes=m$->{1..2}.order_info

# 单库
# spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=m$->{1}.order_info

# 指定主键 生成策略 SNOWFLAKE 雪花算法
spring.shardingsphere.sharding.tables.order_info.key-generator.column=id
spring.shardingsphere.sharding.tables.order_info.key-generator.type=SNOWFLAKE


# 指定库分片策略, 约定 id 值 偶数添加到order_1 库,  奇数添加到order_2 库
spring.shardingsphere.sharding.tables.order_info.database-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.order_info.database-strategy.inline.algorithm-expression=m$->{id % 2 + 1}


# 查看底层 SQL 执行
spring.shardingsphere.props.sql.show=true

YAML 配置

spring:
  shardingsphere:
    # 参数配置,显示sql
    props:
      sql:
        show: true
    # 配置数据源
    datasource:
      # 给每个数据源取别名,下面的ds0,ds1任意取名字
      names: ds0,ds1
      # 给master-ds1每个数据源配置数据库连接信息
      ds0:
        # 配置druid数据源
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://47.115.94.78:3306/order?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT%2b8
        username: root
        password: xxxxxx
        maxPoolSize: 100
        minPoolSize: 5
      # 配置ds1-slave
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://114.215.145.201:3306/order?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT%2b8
        username: root
        password: xxxxx
        maxPoolSize: 100
        minPoolSize: 5
    # 配置默认数据源ds1
    sharding:
      # 配置分表的规则
      tables:
        # order_info 逻辑表名
        order_info:
        	database-strategy: 
        		inline:
        			sharding-column: id # 分片字段(分片键)
        			algorithm-expression: ds$->{id % 2} # 分片算法表达式
        	actual-data-nodes:
            	ds$->{0..1}.order_info

代码

@Test
    public void addOrder(){
        Order order = new Order();
        order.setUserId(12L).setStatus(1L);
        orderMapper.insert(order);
    }

测试运行结果

Actual SQL: m1 ::: INSERT INTO order_info   (user_id, status, id) VALUES (?, ?, ?) ::: [12, 1, 718123009054867457]

水平分表

水平分表:将一张表拆分成多张表,字段一致。可用于存放不同月份的订单

数据库

image-20220405153754120

properties 配置

# shardingjdbc 分片策略 水平分表
spring.shardingsphere.datasource.names=m1

# 一个实体类对应两张表 覆盖
spring.main.allow-bean-definition-overriding=true

# 数据源基础配置
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/course_db?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=xxxxx

# 指定course表分布情况,配置表在那个输数据库里面,表名称都是什么 m1.course_1, m1.course_2 | $->{1..2} 1-2
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m1.course_$->{1..2}

# 指定course表里面主键cid 生成策略 SNOWFLAKE 雪花算法
spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE


# 指定分片策略, 约定 cid 值 偶数添加到course_1表,  奇数添加到course_2 表
spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid
spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid % 2 + 1}

# 查看底层 SQL 执行
spring.shardingsphere.props.sql.show=true

代码

// 测试 水平分表
    @Test
    public void insertDBCourse(){

        for (int i = 0; i < 20; i++) {
            Course course = new Course();

            course.setCname("JAVADemo" + i);
            course.setCstatus("0");
            course.setUserId(105L);

            courseMapper.insert(course);
        }

    }

测试结果

Actual SQL: m1 ::: INSERT INTO course_2   (cname, user_id, cstatus, cid) VALUES (?, ?, ?, ?) ::: [JAVADemo0, 105, 0, 718127725889454081]

Actual SQL: m1 ::: INSERT INTO course_1   (cname, user_id, cstatus, cid) VALUES (?, ?, ?, ?) ::: [JAVADemo1, 105, 0, 718127726719926272]
......

水平分库

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

数据库

image-20220405154845161

properties 配置

# shardingjdbc 分片策略 配置多个数据源 水平分库
spring.shardingsphere.datasource.names=m1,m2

# 一个实体类对应两张表 覆盖
spring.main.allow-bean-definition-overriding=true

# m1数据源基础配置
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/edu_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=xxxxx

# m2数据源基础配置
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://localhost:3306/edu_db_2?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=xxxxx

# 指定水平分库数据库分布情况 及数据库中水平分表的分布情况
#             m1                               m2
#  course_1        course_2         course_1        course_2
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2}

# 指定course表里面主键cid 生成策略 SNOWFLAKE 雪花算法
spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE


# 指定表分片策略, 约定 cid 值 偶数添加到course_1表,  奇数添加到course_2 表
spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid
spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid % 2 + 1}

# 指定数据库分片策略 , 约定 user_id 为偶数 添加 m1 表, 奇数添加 m2 表
# 配置方式1 指定所有表 按此规则划分数据
#spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
#spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=m$->{user_id % 2}


# 配置方式 2 指定表 使用该策略
spring.shardingsphere.sharding.tables.course.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}

# 查看底层 SQL 执行
spring.shardingsphere.props.sql.show=true

代码

插入

// 测试 水平分库
    @Test
    public void insertData(){

        for (int i = 1; i <= 10; i++) {
            Course course = new Course();

            course.setCname("JAVA"+ i);
            course.setCstatus("0"+i);
            course.setUserId(100L + i);

            courseMapper.insert(course);
        }

    }

根据cid查询

@Test
    public void selectById(){

        QueryWrapper<Course> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("cid",718130229758918657L);
        Course course = courseMapper.selectOne(queryWrapper);

        System.out.println(course);
    }

查询全部

@Test
    public void selectAll(){

        List<Course> courses = courseMapper.selectList(new QueryWrapper<Course>());

        System.out.println(courses);

    }

测试

// 插入 约定 cid 值 偶数添加到course_1表,  奇数添加到course_2 表,约定 user_id 为偶数 添加 m1 表, 奇数添加 m2 表
Actual SQL: m2 ::: INSERT INTO course_2   (cname, user_id, cstatus, cid) VALUES (?, ?, ?, ?) ::: [JAVA1, 101, 01, 718130226621579265]

Actual SQL: m1 ::: INSERT INTO course_1   (cname, user_id, cstatus, cid) VALUES (?, ?, ?, ?) ::: [JAVA2, 102, 02, 718130227552714752]

// 查询单个 偶数添加到course_1表,  奇数添加到course_2 表,分片策略约定 cid 奇数 添加到course2表,将两个库的course2表都进行检测。
Actual SQL: m1 ::: SELECT  cid,cname,user_id,cstatus  FROM course_2 
null

Actual SQL: m2 ::: SELECT  cid,cname,user_id,cstatus  FROM course_2 
Course(cid=718130229758918657, cname=JAVA7, userId=107, cstatus=07)

// 查询全部 没有按照分片策略查找,默认全部检索
Actual SQL: m1 ::: SELECT  cid,cname,user_id,cstatus  FROM course_1
Actual SQL: m1 ::: SELECT  cid,cname,user_id,cstatus  FROM course_2
Actual SQL: m2 ::: SELECT  cid,cname,user_id,cstatus  FROM course_1
Actual SQL: m2 ::: SELECT  cid,cname,user_id,cstatus  FROM course_2