官方文档: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及相关核心概念
2.什么是分库分表
3.分库分表的方式
1.垂直分表
把操作数据库某张表,把这张表中一部分字段数据存到一张新表里面,再把这张表另一部分字段数据存到另外一张表里面
2.垂直分库
把单一数据库按照业务进行划分,专库专表
3.水平分库
解决单库数据量大的问题
4.水平分表
4.分库分表应用和问题
1.应用
- 在数据库设计时候考虑垂直分库和垂直分表
- 随着数据量增加,不要马上考虑做水平切分,收下考虑缓存处理,读写分离,使用索引等等方式,如果这些方式不能解决问题,再考虑做水平分库和水平分表
2.分库分表问题
- 跨节点查询问题(分页,排序)
- 多数据源管理问题
5.Sharding-JDBC简介
1.是轻量级的java框架,是增强的JDBC驱动
2.Sharding-jdbc不是做分库分表,主要做两个功能:数据分片和读写分离
6.案例
1.搭建环境
1.Springboot2.2.1+MybatisPlus+sharding-JDBC+Durid连接池
2.创建SpringBoot工程
3.引入依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hejiawang</groupId>
<artifactId>sharding</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sharding</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<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>
<scope>test</scope>
</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>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
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
)
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
打印日志
5.水平分库案例
1.需求分析
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
)
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
查询方法,当只写userid的时候,打印2条sql course_1和course_2都查询了查询方法,写userid和cid的时候,打印1条sql,直接查询到了
6.垂直分库案例
1.需求分析
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,否则会报错
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表都插入了相同的数据
调用deleteDict()方法,生成3条删除sql,所有数据源中的表数据都删除了
8.Sharding-jdbc读写分离
1.读写分离概念
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为从库