ShardingSphere

ShardingSphere-JDBC是一个开源的分布式数据库中间件,用于解决数据库在分布式环境下性能下降的问题。通过垂直和水平分表分库,提升数据库性能。它提供了一个增强版的JDBC驱动,使得在分库分表后的数据操作变得简单。本文详细介绍了如何配置和使用ShardingSphere-JDBC进行水平分表和分库的示例,包括配置数据源、定义分片策略以及进行数据库操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述(what)

  • 它是一套开源的分布式数据库中间件解决方案,合理的在分布式环境下使用关系型数据库操作。
  • 它分为3个部分。分别是ShardingSphere-JDBC、ShardingSphere-Proxy以及未来的ShardingSphere-Sidecar。
  • 本文主要介绍ShardingSphere-JDBC

现存的问题(question)

数据库的数量是不可控的,随着时间和业务的发展,会导致表的数据越来越多,这样子对表进行CRUD操作的时候,性能会很慢。

解决的思路(solution)

可以从两个方面来思考,一是硬件层次,增加硬件,例如CPU、内存、硬盘等。但是这种方法治标不治本。二是软件层次,出现上述问题,首先考虑缓存处理、读写分离、使用索引等方式提高性能。最后考虑对数据库进行分表分库操作。而ShardingSphere则是一个优秀的分布式数据库框架,可以简化对分库分表之后数据的相关操作。

分库分表概念(水平垂直搭配分库分表)

分库分表有两种方式,分别是水平切分和垂直切分。基于分库分表操作,又可以分为4种。接下来一一介绍。

  • 垂直分表:针对数据库的某张表,将这表中的某些字段存储到另外一张表中。例如:有一张课程表,字段有课程名称、课程封面、课程价格、课程描述信息。将课程名称、课程封面和课程价格作为一张课程基本表中的字段存储,将课程描述信息作为另外一张表的字段存储。
  • 垂直分库:针对不同的业务,创建不同的数据库,完成专库专表。例如现有业务是用户下单购买课程。原始思路是将订单表和课程表创建在同一个库中。垂直分库是将订单表和课程表分别存储在不同的数据库中。
  • 水平分库:一般是经过了垂直分库以后,数据量仍然很大。根据业务需求,也无法进行垂直分表分库操作。可以将数据分为几个部分,存储在不同的数据库中。原来数据库中有100w行记录,现在将这些数据分别存储在两个数据库中,这样一个数据库中数据只有50w行记录。
  • 水平分表:针对一个库中数据库仍然很庞大,可以考虑将数据分开存储在不同的表中。例如原来数据库表中有50w条信息,现在可以分为5张表存储,一张表存储10w的数据量。

ShardingSphere-JDBC

它是一个轻量级的java框架,是增强版的JDBC驱动。主要用于简化数据库分库分表之后的数据的操作。例如:数据库分为2个,要求数据的主键id为奇数增加该记录到 第一个库中,否则增加到第2个库中。之前的思路是根据不同的主键id,从而进行不同的CRUD操作。现在有了ShardingSphere-JDBC,通过配置文件配置,再加上一个正常的CRUD操作,即可完成。

demo解析(水平分表)

demo

1.构建Project,导入依赖

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.20</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

2.建数据库,新增实体类

table1
table2

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Course {
    private Long cid;
    private String cname;
    private Long userId;
    private String cstatus;
}

3.使用mp对数据库进行操作。

@Mapper
public interface CourseMapper extends BaseMapper<Course> {
}

4.编写配置类

# shardingjdbc分片策略
# 配置数据源,给数据源起名称 水平分表的配置类
spring.shardingsphere.datasource.names=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/course_db?serverTimezone=GMT%2B8&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456

#指定course表的分布情况,配置表在哪个数据库里面,表的名称都是什么 
# m1.course_1 , m1.course_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表,如果cid是奇数,则添加到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
# 一个实体类对应两张表,覆盖
spring.main.allow-bean-definition-overriding=true

5.测试

@SpringBootTest
class ShardingjdbcdemoApplicationTests {
	 //注入Mapper
    @Autowired
    private CourseMapper courseMapper;
      //测试水平分表
    @Test
    void addCourse1() {
        for (int i = 0; i < 10; i++) {
            Course course = new Course();
            course.setCname("java"+i);
            course.setUserId(100L);
            course.setCstatus("Normal"+i);
            courseMapper.insert(course);
        }
    }
    @Test
    void select1(){
        QueryWrapper<Course> queryWrapper = new QueryWrapper<>();
        //根据自己数据库里面内容进行简单的查询测试
        queryWrapper.eq("cid", 709063885038026752L);
        Course course = courseMapper.selectOne(queryWrapper);
        System.out.println(course.toString());
    }
}

水平分库

在这里插入图片描述
在这里插入图片描述
还是使用那个course类进行测试,只不过创建两个不同的数据库,然后根据cid和user_id的奇偶数来判断存储到哪张表中。
只需要修改application.properties文件即可

# shardingjdbc分片策略
# 配置数据源,给数据源起名称,水平分库+水平分表
spring.shardingsphere.datasource.names=m1,m2

#配置第一个数据源的具体内容,包含连接池,驱动,地址,用户名和密码
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?serverTimezone=GMT%2B8&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456

#配置第二个数据源的具体内容,包含连接池,驱动,地址,用户名和密码
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?serverTimezone=GMT%2B8&useSSL=false
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=123456

# 指定数据库分布情况,数据库里面表的分布情况
# m1,m2 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表,如果cid是奇数,则添加到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表,如果user_id是奇数,则添加到m2表
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}

# 也可以指定库分片策略
#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
# 一个实体类对应两张表,覆盖
spring.main.allow-bean-definition-overriding=true

编写测试代码

  //测试水平分库
    @Test
    void addCourse2() {
        Course course = new Course();
        course.setCname("javademo1");
        //分库根据 user_id
        course.setUserId(100L);
        course.setCstatus("Normal1");
        courseMapper.insert(course);
    }
    @Test
    void select2(){
        QueryWrapper<Course> wrapper = new QueryWrapper<>();
        //设置 userid 值 own
        wrapper.eq("user_id ",100L);
        //设置 cid 值 own
        wrapper.eq("cid",709073553256873985L);
        Course course = courseMapper.selectOne(wrapper);
        System.out.println(course);
    }

垂直分库

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

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "t_user")  //指定对应表
public class User {
    private Long userId;
    private String username;
    private String ustatus;
}
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
# 配置数据源,给数据源起名称,垂直分库
spring.shardingsphere.datasource.names=m1,m2,m0
#垂直分表
#配置第三个数据源的具体内容,包含连接池,驱动,地址,用户名和密码
spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT%2B8&useSSL=false
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=123456

# 指定数据库分布情况,数据库里面表的分布情况
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=m$->{0}.t_user

#指定t_user表里面主键user_id 生成策略 SNOWFLAKE
spring.shardingsphere.sharding.tables.t_user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.t_user.key-generator.type=SNOWFLAKE

#指定表的分片策略 约定cid值偶数添加到course_1表,如果cid是奇数,则添加到course_2表
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression=t_user

测试

 //测试垂直分库
    @Test
    public void add3() {
        User user = new User();
        user.setUsername("lucy");
        user.setUstatus("a");
        userMapper.insert(user);
    }
    @Test
    void select3(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",709083354305134593L);
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }

配置公共表

公共表定义:存储固定数据的表,表数据很少发生变化,查询的时候经常会关联。在每个需要的数据库创建相同结构的表结构。
在这里插入图片描述

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "t_udict")
public class Udict {
    private Long dictid;
    private String ustatus;
    private String uvalue;
}
@Mapper
public interface UdictMapper extends BaseMapper<Udict> {
}
# shardingjdbc分片策略
# 配置数据源,给数据源起名称,公共表配置
spring.shardingsphere.datasource.names=m1,m2,m0

#配置第一个数据源的具体内容,包含连接池,驱动,地址,用户名和密码
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?serverTimezone=GMT%2B8&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456

#配置第二个数据源的具体内容,包含连接池,驱动,地址,用户名和密码
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?serverTimezone=GMT%2B8&useSSL=false
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=123456


# 指定数据库分布情况,数据库里面表的分布情况
# m1,m2 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表,如果cid是奇数,则添加到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表,如果user_id是奇数,则添加到m2表
#spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
#spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}

# 也可以指定库分片策略
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
# 一个实体类对应两张表,覆盖
spring.main.allow-bean-definition-overriding=true

#垂直分表
#配置第三个数据源的具体内容,包含连接池,驱动,地址,用户名和密码
spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT%2B8&useSSL=false
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=123456

# 指定数据库分布情况,数据库里面表的分布情况
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=m$->{0}.t_user

#指定t_user表里面主键user_id 生成策略 SNOWFLAKE
spring.shardingsphere.sharding.tables.t_user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.t_user.key-generator.type=SNOWFLAKE

#指定表的分片策略 约定cid值偶数添加到course_1表,如果cid是奇数,则添加到course_2表
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression=t_user

#配置公共表
spring.shardingsphere.sharding.broadcast-tables=t_udict
spring.shardingsphere.sharding.tables.t_udict.key-generator.column=dictid
spring.shardingsphere.sharding.tables.t_udict.key-generator.type=SNOWFLAKE

测试

  @Test
    public void addDict() {
        Udict udict = new Udict();
        udict.setUstatus("a");
        udict.setUvalue("已启用");
        udictMapper.insert(udict);
    }

    @Test
    public void deleteDict() {
        QueryWrapper<Udict> wrapper = new QueryWrapper<>();
        //设置 userid 值
        wrapper.eq("dictid",709088530961268737L);
        udictMapper.delete(wrapper);
    }

读写分离(概念)

为了确保数据库产品的稳定性,很多数据库具备双机热备功能。也就是有2台数据库服务器,一台负责对外的CUD操作,一台负责对外的R操作。主服务器负责处理增、删、改操作。从库负责查询操作,减少数据的访问量。

原理

主从复制:当主服务器有CUD操作时,从服务器自动获取主服务器的操作,并更新自己的从库。
读写分离:主CUD,从R

mysql的主从复制原理是通过binlog日志来完成,主服务器会将CUD操作记录形成binlog日志,从服务器实时监控主服务器,读取并解析日志,完成主从复制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值