ShardingSphere水平垂直分库分表和公共表

Posted Java.L

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ShardingSphere水平垂直分库分表和公共表相关的知识,希望对你有一定的参考价值。

目录

一、ShardingSphere简介

Apache ShardingSphere 是一个开源的分布式数据库中间件解决方案组成的生态圈,且它的产品有Sharding-JDBC和Sharding-Proxy组成(他们两个之间是独立的),同时又能混合部署(组合起来一起使用)。它们都提供了标准化的数据分片、分布式事务和数据库的治理能力,可适用如Java、云原生开发的应用场景。

ShardingSphere定位是关系型数据库中间件,目的是充分为了合理地在分布式的场景下利用关系型数据库的计算能力和存储能力,而不是实现一个全新的关系型数据库。

二、ShardingSphere-分库分表

1、垂直拆分

(1)垂直分库

垂直分库:把单一的数据库按照业务的不同进行划分(专库专表)

(2)垂直分表

操作数据库中的某张表,我们把这张表里面的一部分字段拿出来存储到一张新的表里,剩下的字段放在另一张表里。

2、水平拆分

(1)水平分库

水平分库相当于把数据库水平切割,原来一个表中的数据可能会分配到不同的数据库中,这就是水平分库。

(2)水平分表

水平分表就是把表中的数据进行了水平切割,意味着按照行进行切割,也就是说不同行的数据被切割后可能在不同的表中。

三、水平分库操作

1、创建数据库和表

-- 创建两个数据库
CREATE DATABASE edu_db_1;
CREATE DATABASE edu_db_2;
-- 需要在两个数据库中都执行下面的脚本
CREATE TABLE course_1(
    cid BIGINT(20) PRIMARY KEY,
    cname VARCHAR(20) NOT NULL,
    user_id BIGINT(20) NOT NULL,
    cstatus VARCHAR(20) NOT NULL
);


CREATE TABLE course_2(
    cid BIGINT(20) PRIMARY KEY,
    cname VARCHAR(20) NOT NULL,
    user_id BIGINT(20) NOT NULL,
    cstatus VARCHAR(20) NOT NULL
);

2、配置分片的规则

spring.shardingsphere.datasource.names=ds-1,ds-2

spring.shardingsphere.datasource.ds-1.jdbc-url=jdbc:mysql://localhost:3306/edu_db_1?serverTimezone=Asia/Shanghai&useSSL=false
spring.shardingsphere.datasource.ds-1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds-1.username=root
spring.shardingsphere.datasource.ds-1.password=root

spring.shardingsphere.datasource.ds-2.jdbc-url=jdbc:mysql://localhost:3306/edu_db_2?serverTimezone=Asia/Shanghai&useSSL=false
spring.shardingsphere.datasource.ds-2.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds-2.username=root
spring.shardingsphere.datasource.ds-2.password=root


spring.main.allow-bean-definition-overriding=true


spring.shardingsphere.sharding.tables.course.actual-data-nodes=ds-$->1..2.course_$->1..2


spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE

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

spring.shardingsphere.sharding.tables.course.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=ds-$->user_id % 2 + 1


spring.shardingsphere.props.sql.show=true

3、测试类

// ------------- 测试分库 ---------------------
    @Test
    void addCorseFpdb() 
        Course course = new Course();
        course.setCname("java01");
        // 根据user_id进行分库,偶数是在edu_db_1,基数是在edu_db_2
        course.setUserId(100L);
        course.setCstatus("已启用");
        courseMapper.insert(course);
    

四、水平分表操作

1、引入依赖

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

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

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

    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
        <version>4.0.0</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>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2、创建数据库、表

create table course_1(
    cid bigint(20) primary key,
    cname varchar(20) not null,
    user_id bigint(20) not null,
    cstatus varchar(20) not null
);

create table course_2(
    cid bigint(20) primary key,
    cname varchar(20) not null,
    user_id bigint(20) not null,
    cstatus varchar(20) not null
);

3、分片策略

spring.shardingsphere.datasource.names=ds-0

spring.shardingsphere.datasource.ds-0.jdbc-url=jdbc:mysql://localhost:3306/course_db?serverTimezone=Asia/Shanghai&useSSL=false
spring.shardingsphere.datasource.ds-0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds-0.username=root
spring.shardingsphere.datasource.ds-0.password=root


spring.main.allow-bean-definition-overriding=true


spring.shardingsphere.sharding.tables.course.actual-data-nodes=ds-0.course_$->1..2


spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE

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


spring.shardingsphere.props.sql.show=true

4、编写代码实现

(1)实体类

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Course 
    private Long cid;
    private String cname;
    private Long userId;
    private String cstatus;

(2)编写Mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chenxin.shardingsphere.entity.Course;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface CourseMapper extends BaseMapper<Course> 

(3)启动类修改(添加扫描mapper的入口)

@SpringBootApplication
@MapperScan("com.chenxin.shardingsphere.mapper")
public class ShardingsphereApplication 

    public static void main(String[] args) 
        SpringApplication.run(ShardingsphereApplication.class, args);
    


(4)测试类(采用springboot给我们提供的)

@SpringBootTest
class ShardingsphereApplicationTests 

    @Resource
    CourseMapper courseMapper;
    
    @Test
    void addCourse() 
        Course course = null;
        for (int i = 0; i < 100; i++) 
            course = new Course();
            course.setCname("Java");
            course.setUserId(1000L);
            course.setCstatus("Nor1");
            courseMapper.insert(course);
        
    


五、垂直分库/分表操作

1、创建数据库、表

CREATE DATABASE user_db;
USE user_db;
CREATE TABLE T_USER(
	user_id BIGINT(20) NOT NULL PRIMARY KEY,
    username VARCHAR(100) NOT NULL,
    ustatus VARCHAR(50) NOT NULL
);

2、分片策略

spring.shardingsphere.datasource.names=ds-1,ds-2,ds-3

spring.shardingsphere.datasource.ds-1.jdbc-url=jdbc:mysql://localhost:3306/edu_db_1?serverTimezone=Asia/Shanghai&useSSL=false
spring.shardingsphere.datasource.ds-1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds-1.username=root
spring.shardingsphere.datasource.ds-1.password=root

spring.shardingsphere.datasource.ds-2.jdbc-url=jdbc:mysql://localhost:3306/edu_db_2?serverTimezone=Asia/Shanghai&useSSL=false
spring.shardingsphere.datasource.ds-2.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds-2.username=root
spring.shardingsphere.datasource.ds-2.password=root

spring.shardingsphere.datasource.ds-3.jdbc-url=jdbc:mysql://localhost:3306/user_db?serverTimezone=Asia/Shanghai&useSSL=false
spring.shardingsphere.datasource.ds-3.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-3.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds-3.username=root
spring.shardingsphere.datasource.ds-3.password=root


spring.main.allow-bean-definition-overriding=true


# spring.shardingsphere.sharding.tables.course.actual-data-nodes=ds-$->1..2.course_$->1..2
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=ds-$->3.t_user


spring.shardingsphere.sharding.tables.t_user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.t_user.key-generator.type=SNOWFLAKE

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.props.sql.show=true

3、编写代码实现

(1)创建User实体类

import lombok.Data;
import lombok.ToString;

// 实体类添加注解
@TableName(value = "t_user")
@Data
@ToString
public class User 
    private Long userId;
    private String username;
    private String ustatus;

(2)Mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chenxin.shardingsphere.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> 

4、测试

// ------------- 测试垂直分库 ----------------------
@Test
void addUser() 
    User user = new User();
    user.setUsername("chenxin");
    user.setUstatus("a");
    userMapper.insert(user);

六、公共表

1、概念

存储固定数据的表,表里面的数据很少发生变化,查询的时候经常进行关联查询

在每个数据库中创建出相同的结构的表(我们将每个数据库中共有的表成为公共表)

2、实现

(1)在三个数据库中创建公共表

CREATE TABLE t_udict(
	dicid bigint(20) primary key,
    ustatus varchar(20) not null,
    uvalue varchar(100) not null
);

(2)公共表的配置

spring.shardingsphere.sharding.broadcast-tables=t_udict
spring.shardingsphere.sharding.tables.t_udict.key-generator.column=dicid
spring.shardingsphere.sharding.tables.t_udict.key-generator.type=SNOWFLAKE

(3)测试代码

创建实体类

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;

@Data
@ToString
@TableName(value = "t_udict")
public class Udict 
    private Integer dicid;
    private String ustatus;
    private String uvalue;

Mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chenxin.shardingsphere.entity.Udict;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UdictMapper extends BaseMapper<Udict> 

测试代码

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


@Test
void updateDict() 
    Udict udict = new Udict();
    udict.setDicid(792033627201339393L);
    udict.setUstatus("1");
    udict.setUvalue("未启用");
    udictMapper.updateById(udict);

3、相关问题及解决方法

(1)Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named ‘null’ in ‘class com.chenxin.shardingsphere.entity.Udict’

问题原因
数据库中字段名和实体类中相差太大,程序自己对应不上

解决方法

// 需要在实体类指定主键是哪一个属性
@Data
@ToString
@TableName(value = "t_udict")
public class Udict 
    @TableId
    private Long dicid;
    private String ustatus;
    private String uvalue;

以上是关于ShardingSphere水平垂直分库分表和公共表的主要内容,如果未能解决你的问题,请参考以下文章

shardingsphere

什么是分库分表?ShardingSphere解决方案

ShardingSphere实践——ShardingSphere介绍

ShardingSphere实践——ShardingSphere介绍

Springboot2.x + ShardingSphere 实现分库分表

面试官: ShardingSphere 学一下吧