Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)

官方文档:https://shardingsphere.apache.org/document/current/cn/overview/
学习视频:https://www.bilibili.com/video/BV1LK411s7RX?p=2&vd_source=fc7fa697b97f292319c5b0cde4755484
代码:https://gitee.com/wangzai6/sharding-jdbc.git

1.什么是ShardingSphere及相关核心概念

在这里插入图片描述
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第1张图片
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第2张图片

2.什么是分库分表

在这里插入图片描述
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第3张图片

3.分库分表的方式

1.垂直分表

把操作数据库某张表,把这张表中一部分字段数据存到一张新表里面,再把这张表另一部分字段数据存到另外一张表里面
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第4张图片

2.垂直分库

把单一数据库按照业务进行划分,专库专表
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第5张图片

3.水平分库

解决单库数据量大的问题
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第6张图片

4.水平分表

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第7张图片

4.分库分表应用和问题

1.应用

  1. 在数据库设计时候考虑垂直分库和垂直分表
  2. 随着数据量增加,不要马上考虑做水平切分,收下考虑缓存处理,读写分离,使用索引等等方式,如果这些方式不能解决问题,再考虑做水平分库和水平分表
    Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第8张图片

2.分库分表问题

  1. 跨节点查询问题(分页,排序)
    Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第9张图片
  2. 多数据源管理问题

5.Sharding-JDBC简介

1.是轻量级的java框架,是增强的JDBC驱动

2.Sharding-jdbc不是做分库分表,主要做两个功能:数据分片和读写分离

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第10张图片

6.案例

1.搭建环境

1.Springboot2.2.1+MybatisPlus+sharding-JDBC+Durid连接池

2.创建SpringBoot工程

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第11张图片
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第12张图片

3.引入依赖

pom.xml



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.1.RELEASE
         
    
    com.hejiawang
    sharding
    0.0.1-SNAPSHOT
    sharding
    Demo project for Spring Boot
    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            com.alibaba
            druid-spring-boot-starter
            1.1.20
        

        
            mysql
            mysql-connector-java
        
        
            org.apache.shardingsphere
            sharding-jdbc-spring-boot-starter
            4.0.0-RC1
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.0.5
        
        
            org.projectlombok
            lombok
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

4.水平分表案例

1.创建数据库course_db

2.在数据库创建两张表course_1和course_2

create table course_1(
    cid bigint(20) PRIMARY KEY ,
    cname varchar(50) not null ,
    user_id bigint(20) not null ,
    cstatus varchar(10) not null
)
create table course_2(
    cid bigint(20) PRIMARY KEY ,
    cname varchar(50) not null ,
    user_id bigint(20) not null ,
    cstatus varchar(10) not null
)

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第13张图片

3.约定规则,如果添加课程id是偶数把数据添加到course_1,如果是奇数添加到course_2

Course

package com.hejiawang.sharding.entity;

import lombok.Data;

/**
 * @description:
 * @author: Mr.Wang
 * @create: 2022-07-13 16:34
 **/
@Data
public class Course {
    private Long cid;
    private String cname;
    private Long userId;
    private String cstatus;
}

CourseMapper

package com.hejiawang.sharding.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hejiawang.sharding.entity.Course;
import org.springframework.stereotype.Repository;

/**
 * @description:
 * @author: Mr.Wang
 * @create: 2022-07-13 16:35
 **/
@Repository
public interface CourseMapper extends BaseMapper<Course> {
}

ShardingApplication

package com.hejiawang.sharding;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.hejiawang.sharding.mapper")
public class ShardingApplication {

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

application.properties

# shardingjdbc分片策略
#配置数据源,给数据源起名称
spring.shardingsphere.datasource.names=ds1

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

# 配置数据源具体内容,包含连接池,驱动地址,用户名和密码
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
#jdk1.8 com.mysql.cj.jdbc.Driver
#jdk1.8以下 om.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://ip:端口/course_db?serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds1.username = xxx
spring.shardingsphere.datasource.ds1.password = xxx

#指定course表分布情况,配置表在哪个数据库里面,表名称都是什么 ds1.course_1 ds1.course_2
spring.shardingsphere.sharding.tables.course.actual-data-nodes=ds1.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

测试类 ShardingApplicationTests

package com.hejiawang.sharding;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hejiawang.sharding.entity.Course;
import com.hejiawang.sharding.mapper.CourseMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingApplicationTests {
//  注入mapper
    @Autowired
    private CourseMapper courseeMapper;
//    添加课程
    @Test
    public void addCourse(){
        for (int i = 0 ; i <=10 ; i++){
            Course course = new Course();
            course.setCname("java");
            course.setUserId(100L);
            course.setCstatus("Normal"+i);
            courseeMapper.insert(course);
        }
    }

//    查询课程方法
    @Test
    public void findCourse(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("cid",754034712887951360L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }
}

调用测试添加方法
cid通过雪花算法生成,如果为奇数则插入course_2,偶数则插入course_1
打印日志
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第14张图片

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第15张图片
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第16张图片

5.水平分库案例

1.需求分析

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第17张图片

2.创建数据库和表

create table course_1(
    cid bigint(20) PRIMARY KEY ,
    cname varchar(50) not null ,
    user_id bigint(20) not null ,
    cstatus varchar(10) not null
)
create table course_2(
    cid bigint(20) PRIMARY KEY ,
    cname varchar(50) not null ,
    user_id bigint(20) not null ,
    cstatus varchar(10) not null
)

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第18张图片

3.在springboot配置数据库分片规则

application.properties

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

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

# 配置第一个数据源具体内容,包含连接池,驱动地址,用户名和密码
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
#jdk1.8 com.mysql.cj.jdbc.Driver
#jdk1.8以下 om.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://ip:端口/edu_db_1?serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds1.username = xxx
spring.shardingsphere.datasource.ds1.password = xxx

# 配置第二个数据源具体内容,包含连接池,驱动地址,用户名和密码
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
#jdk1.8 com.mysql.cj.jdbc.Driver
#jdk1.8以下 om.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://ip:端口/edu_db_2?serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds2.username = xxx
spring.shardingsphere.datasource.ds2.password = xxx

#指定数据库分布情况,数据库里面表分布情况
# ds1 ds2  course_1 course_2
spring.shardingsphere.sharding.tables.course.actual-data-nodes=ds$->{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是偶数添加ds1,是奇数添加ds2
# 数据库中所有表的规则
# spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
# spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{userid % 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}


#打开sql输出日志
spring.shardingsphere.props.sql.show=true

4.编写测试方法

package com.hejiawang.sharding;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hejiawang.sharding.entity.Course;
import com.hejiawang.sharding.mapper.CourseMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingApplicationTests {
//  注入mapper
    @Autowired
    private CourseMapper courseeMapper;
//    ===============测试水平分库=================
    @Test
    public void addCourseDb(){
            Course course = new Course();
            course.setCname("C++");
//            分库根据user_id
            course.setUserId(100L);
            course.setCstatus("Normal");
            courseeMapper.insert(course);
    }

    @Test
    public void findCourseDb(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("user_id",100L);
        wrapper.eq("cid",754375827029753857L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }
//    ===============测试水平分表=================
//    添加课程
    @Test
    public void addCourse(){
        for (int i = 0 ; i <=10 ; i++){
            Course course = new Course();
            course.setCname("C语言");
            course.setUserId(100L);
            course.setCstatus("Normal"+i);
            courseeMapper.insert(course);
        }
    }

//    查询课程方法
    @Test
    public void findCourse(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("cid",754034712887951360L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }
}

执行水平分库方法addCourseDb(),查看打印结果在这里插入图片描述
数据库为ds1配置的数据源edu_db_1 下的course_2
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第19张图片
查询方法,当只写userid的时候,打印2条sql course_1和course_2都查询了
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第20张图片查询方法,写userid和cid的时候,打印1条sql,直接查询到了
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第21张图片

6.垂直分库案例

1.需求分析

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第22张图片
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第23张图片

2.创建数据库和表

create table t_user(
    user_id bigint(20) not null ,
    username varchar(100) not null,
    ustatus varchar(50) not null 
)

在这里插入图片描述

3.编写测试方法

注意 User实体类要映射到表名t_user,否则会报错
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第24张图片
User

package com.hejiawang.sharding.entity;

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

/**
 * @description:
 * @author: Mr.Wang
 * @create: 2022-07-14 16:33
 **/
@Data
@TableName(value = "t_user") //指定对应表
public class User {
    private Long userId;
    private String username;
    private String ustatus;
}

UserMapper

package com.hejiawang.sharding.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hejiawang.sharding.entity.User;
import org.springframework.stereotype.Repository;

@Repository
public interface UserMapper extends BaseMapper<User> {
}

配置规则application.properties

# shardingjdbc分片策略
#配置数据源,给数据源起名称,水平分库
spring.shardingsphere.datasource.names=ds1,ds2,ds3

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

# 配置第一个数据源具体内容,包含连接池,驱动地址,用户名和密码
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
#jdk1.8 com.mysql.cj.jdbc.Driver
#jdk1.8以下 om.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://ip:端口/edu_db_1?serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds1.username = xxx
spring.shardingsphere.datasource.ds1.password = xxx

# 配置第二个数据源具体内容,包含连接池,驱动地址,用户名和密码
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
#jdk1.8 com.mysql.cj.jdbc.Driver
#jdk1.8以下 om.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://ip:端口/edu_db_2?serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds2.username = xxx
spring.shardingsphere.datasource.ds2.password = xxx


# 配置第三个数据源具体内容,包含连接池,驱动地址,用户名和密码
spring.shardingsphere.datasource.ds3.type=com.alibaba.druid.pool.DruidDataSource
#jdk1.8 com.mysql.cj.jdbc.Driver
#jdk1.8以下 om.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds3.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds3.url=jdbc:mysql://ip:端口/user_db?serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds3.username = xxx
spring.shardingsphere.datasource.ds3.password = xxx

# 配置user_db数据库里面t_user 专库专表
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

#指定数据库分布情况,数据库里面表分布情况
# ds1 ds2  course_1 course_2
spring.shardingsphere.sharding.tables.course.actual-data-nodes=ds$->{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是偶数添加ds1,是奇数添加ds2
# 数据库中所有表的规则
# spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
# spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{userid % 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}


#打开sql输出日志
spring.shardingsphere.props.sql.show=true

测试类

package com.hejiawang.sharding;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hejiawang.sharding.entity.Course;
import com.hejiawang.sharding.entity.User;
import com.hejiawang.sharding.mapper.CourseMapper;
import com.hejiawang.sharding.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingApplicationTests {
//  注入mapper
    @Autowired
    private CourseMapper courseeMapper;
    @Autowired
    private UserMapper userMapper;

//    ===============测试垂直分库=================
    @Test
    public void addUserDb(){
        User user = new User();
        user.setUsername("飞哥");
        user.setUstatus("牛逼");
        userMapper.insert(user);
    }
        @Test
        public void findUserDb(){
            QueryWrapper<User> wrapper = new QueryWrapper();
            wrapper.eq("user_id",754388854030467073L);
            User user = userMapper.selectOne(wrapper);
            System.out.println(user);
        }
//    ===============测试水平分库=================
    @Test
    public void addCourseDb(){
            Course course = new Course();
            course.setCname("C++");
//            分库根据user_id
            course.setUserId(100L);
            course.setCstatus("Normal");
            courseeMapper.insert(course);
    }

    @Test
    public void findCourseDb(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("user_id",100L);
        wrapper.eq("cid",754375827029753857L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }
//    ===============测试水平分表=================
//    添加课程
    @Test
    public void addCourse(){
        for (int i = 0 ; i <=10 ; i++){
            Course course = new Course();
            course.setCname("C语言");
            course.setUserId(100L);
            course.setCstatus("Normal"+i);
            courseeMapper.insert(course);
        }
    }

//    查询课程方法
    @Test
    public void findCourse(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("cid",754034712887951360L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }

}

运行addUserDb()方法,走ds3数据源
在这里插入图片描述
运行findUserDb()方法,走ds3数据源

在这里插入图片描述

7.Sharding-jdbc公共表

1.公共表

存储固定数据的表,表数据很少发生变化,查询时经常要关联的表
在每个数据库中创建相同结构公共表

2.创建数据库和表

在edu_db_1,edu_db_2,user_db中创建公共表
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

create table t_udict(
    dictid bigint(20) primary key ,
    ustatus varchar(100) not null ,
    uvalue varchar(100) not null
)

3.配置文件中配置规则

application.properties

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

4.编写测试规则

1.创建新实体类和mapper
Udict

package com.hejiawang.sharding.entity;

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

/**
 * @description:
 * @author: Mr.Wang
 * @create: 2022-07-14 20:54
 **/
@Data
@TableName(value = "t_udict")
public class Udict {
    private Long dictid;
    private String ustatus;
    private String uvalue;
}

UdictMapper

package com.hejiawang.sharding.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hejiawang.sharding.entity.Udict;
import org.springframework.stereotype.Repository;

@Repository
public interface UdictMapper extends BaseMapper<Udict> {
}

测试类

package com.hejiawang.sharding;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hejiawang.sharding.entity.Course;
import com.hejiawang.sharding.entity.Udict;
import com.hejiawang.sharding.entity.User;
import com.hejiawang.sharding.mapper.CourseMapper;
import com.hejiawang.sharding.mapper.UdictMapper;
import com.hejiawang.sharding.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingApplicationTests {
//  注入mapper
    @Autowired
    private CourseMapper courseeMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UdictMapper udictMapper;
//    ===============测试公共表=================
    @Test
    public void addDict(){
        Udict udict = new Udict();
        udict.setUstatus("状态非常好");
        udict.setUvalue("已启用");
        udictMapper.insert(udict);
    }
    @Test
    public void deleteDict(){
        QueryWrapper<Udict> wrapper = new QueryWrapper<>();
        wrapper.eq("dictid",754449834907271169L);
        udictMapper.delete(wrapper);
    }

//    ===============测试垂直分库=================
    @Test
    public void addUserDb(){
        User user = new User();
        user.setUsername("飞哥");
        user.setUstatus("牛逼");
        userMapper.insert(user);
    }

        @Test
        public void findUserDb(){
            QueryWrapper<User> wrapper = new QueryWrapper();
            wrapper.eq("user_id",754389540776443905L);
            User user = userMapper.selectOne(wrapper);
            System.out.println(user);
        }
//    ===============测试水平分库=================
    @Test
    public void addCourseDb(){
            Course course = new Course();
            course.setCname("C++");
//            分库根据user_id
            course.setUserId(100L);
            course.setCstatus("Normal");
            courseeMapper.insert(course);
    }

    @Test
    public void findCourseDb(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("user_id",100L);
        wrapper.eq("cid",754375827029753857L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }
//    ===============测试水平分表=================
//    添加课程
    @Test
    public void addCourse(){
        for (int i = 0 ; i <=10 ; i++){
            Course course = new Course();
            course.setCname("C语言");
            course.setUserId(100L);
            course.setCstatus("Normal"+i);
            courseeMapper.insert(course);
        }
    }

//    查询课程方法
    @Test
    public void findCourse(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("cid",754034712887951360L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }
}

调用addDict()方法,所有配置数据源下的t_udict表都插入了相同的数据
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第25张图片
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第26张图片
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第27张图片
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第28张图片
调用deleteDict()方法,生成3条删除sql,所有数据源中的表数据都删除了
在这里插入图片描述

8.Sharding-jdbc读写分离

1.读写分离概念

Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第29张图片
Sharding-jdbc 概念及Demo(4.0.0-RC1版本Demo)_第30张图片
sharding-jdbc通过对sql语句语义分析,实现读写分离过程,不会做数据库同步

2.mysql配置读写分离

参考前面文章
https://blog.csdn.net/Persistence___/article/details/123215121?spm=1001.2014.3001.5501

3.sharding-jdbc操作

User

package com.hejiawang.sharding.entity;

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

/**
 * @description:
 * @author: Mr.Wang
 * @create: 2022-07-14 16:33
 **/
@Data
@TableName(value = "t_user") //指定对应表
public class User {
    private Long userId;
    private String username;
    private String ustatus;
}

UserMapper

package com.hejiawang.sharding.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hejiawang.sharding.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
}

application配置

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

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

# 配置第三个数据源具体内容,包含连接池,驱动地址,用户名和密码
# user_db主服务器
spring.shardingsphere.datasource.ds3.type=com.alibaba.druid.pool.DruidDataSource
#jdk1.8 com.mysql.cj.jdbc.Driver
#jdk1.8以下 om.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds3.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds3.url=jdbc:mysql://ip:端口/user_db?serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.ds3.username = xxx
spring.shardingsphere.datasource.ds3.password = xxx

# user_db从服务器
spring.shardingsphere.datasource.s3.type=com.alibaba.druid.pool.DruidDataSource
#jdk1.8 com.mysql.cj.jdbc.Driver
#jdk1.8以下 om.mysql.jdbc.Driver
spring.shardingsphere.datasource.s3.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.s3.url=jdbc:mysql://ip:端口/user_db?serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.s3.username = xxx
spring.shardingsphere.datasource.s3.password = xxx

# 主库从库逻辑数据源定义 ds3为user_db
spring.shardingsphere.sharding.master-slave-rules.ms3.master-data-source-name=ds3
spring.shardingsphere.sharding.master-slave-rules.ms3.slave-data-source-names=s3
# 配置user_db数据库里面t_user 专库专表
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=ms3.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



#打开sql输出日志
spring.shardingsphere.props.sql.show=true

测试类

package com.hejiawang.sharding;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hejiawang.sharding.entity.Course;
import com.hejiawang.sharding.entity.Udict;
import com.hejiawang.sharding.entity.User;
import com.hejiawang.sharding.mapper.CourseMapper;
import com.hejiawang.sharding.mapper.UdictMapper;
import com.hejiawang.sharding.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingApplicationTests {
//  注入mapper
    @Autowired
    private CourseMapper courseeMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UdictMapper udictMapper;
//    ===============测试读写分离=================
    @Test
    public void addUserDbMaster(){
        User user = new User();
        user.setUsername("肥宅子");
        user.setUstatus("牛逼!!!");
        userMapper.insert(user);
    }
    @Test
    public void findUserDbSlave(){
        QueryWrapper<User> wrapper = new QueryWrapper();
        wrapper.eq("user_id",754389540776443905L);
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }
//    ===============测试公共表=================
    @Test
    public void addDict(){
        Udict udict = new Udict();
        udict.setUstatus("状态非常好");
        udict.setUvalue("已启用");
        udictMapper.insert(udict);
    }
    @Test
    public void deleteDict(){
        QueryWrapper<Udict> wrapper = new QueryWrapper<>();
        wrapper.eq("dictid",754449834907271169L);
        udictMapper.delete(wrapper);
    }
//    ===============测试垂直分库=================
    @Test
    public void addUserDb(){
        User user = new User();
        user.setUsername("飞哥");
        user.setUstatus("牛逼");
        userMapper.insert(user);
    }

        @Test
        public void findUserDb(){
            QueryWrapper<User> wrapper = new QueryWrapper();
            wrapper.eq("user_id",754389540776443905L);
            User user = userMapper.selectOne(wrapper);
            System.out.println(user);
        }
//    ===============测试水平分库=================
    @Test
    public void addCourseDb(){
            Course course = new Course();
            course.setCname("C++");
//            分库根据user_id
            course.setUserId(100L);
            course.setCstatus("Normal");
            courseeMapper.insert(course);
    }

    @Test
    public void findCourseDb(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("user_id",100L);
        wrapper.eq("cid",754375827029753857L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }
//    ===============测试水平分表=================
//    添加课程
    @Test
    public void addCourse(){
        for (int i = 0 ; i <=10 ; i++){
            Course course = new Course();
            course.setCname("C语言");
            course.setUserId(100L);
            course.setCstatus("Normal"+i);
            courseeMapper.insert(course);
        }
    }

//    查询课程方法
    @Test
    public void findCourse(){
        QueryWrapper<Course> wrapper = new QueryWrapper();
//        wrapper.eq("cid",754034711998758913L);
        wrapper.eq("cid",754034712887951360L);
        Course course = courseeMapper.selectOne(wrapper);
        System.out.println(course);
    }
}

调用addUserDbMaster()方法,insert方法走的ds3数据源,ds3为主库在这里插入图片描述
调用findUserDbSlave()方法,select方法走的s3数据源,s3为从库

在这里插入图片描述

你可能感兴趣的:(Java,java,前端,服务器)