shardingsphere(2)—部分实战篇

举报
小白弟弟 发表于 2022/01/03 00:35:20 2022/01/03
【摘要】 2、ShardingSphere 2.1、什么是ShardingSphere?地址:https://shardingsphere.apache.org/index_zh.html[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RswOjRqQ-1631071303442)(https://gitee.com/zhouzhz/images/raw/master/...

2、ShardingSphere

2.1、什么是ShardingSphere?

地址:https://shardingsphere.apache.org/index_zh.html

image.png

ShardingJDBC:

image-20210905203757797

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

ShardingProxy

image-20210905203835652

ShardingProxy定位为透明化的数据库代理端,提供封装了数据库⼆进制协议的服务端版本,⽤于完成对异构语⾔的⽀持。⽬前提供 MySQL 和 PostgreSQL 版本,它可以使⽤任何兼容 MySQL/PostgreSQL 协议的访问客⼾端。

两种方式的区别:

Sharding-JDBC Sharding-Proxy
数据库 任意 MySQL/PostgreSQL
连接消耗数
异构语言 仅java 任意
性能 损耗低 损耗略高
无中心化
静态入口

ShardingJDBC只是客户端的一个工具包,可以理解为一个特殊的JDBC驱动包,所有分库分表逻辑均由业务方自己控制,所以他的功能相对灵活,支持的数据库也非常多,但是对业务侵入大,需要业务方自己定制所有的分库分表逻辑。

ShardingProxy是一个独立部署的服务,对业务方无侵入,业务方可以像用一个普通的MySQL服务一样进行数据交互,基本上感觉不到后端分库分表逻辑的存在,但是这也意味着功能会比较固定,能够支持的数据库也比较少。

2.2、核心概念:

shardingjdbc的核心功能是数据分片和读写分离,通过ShardingJDBC,应用可以透明的使用JDBC访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分布。

  • 逻辑表:水平拆分的数据库的相同逻辑和数据结构表的总称

  • 真实表:在分片的数据库中真实存在的物理表。

  • 数据节点:数据分片的最小单元。由数据源名称和数据表组成

  • 绑定表:分片规则一致的主表和子表。

  • 广播表:也叫公共表,指素有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中都完全一致。例如字典表。

  • 分片键:用于分片的数据库字段,是将数据库(表)进行水平拆分的关键字段。SQL中若没有分片字段,将会执行全路由,性能会很差。

  • 分片算法:通过分片算法将数据进行分片,支持通过=、BETWEEN和IN分片。分片算法需要由应用开发者自行实现,可实现的灵活度非常高。

  • 分片策略:真正用于进行分片操作的是分片键+分片算法,也就是分片策略。在ShardingJDBC中一般采用基于Groovy表达式的inline分片策略,通过一个包含分片键的算法表达式来制定分片策略,如t_user_$->{u_id%8}标识根据u_id模8,分成8张表,表名称为t_user_0到t_user_7。

2.3、分库分表实战

pom依赖

<?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>
    <groupId>com.zhz</groupId>
    <artifactId>sharding-sphere-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sharding-sphere-demo</name>
    <description>Spring Boot集成ShardingSphere做分库分表</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>
        <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</artifactId>
            <version>1.1.22</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </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>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.1.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

pojo实体类

package com.zhz.shardingspheredemo.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

  /**  
    * @Description: 课程实体类
    * 
    * @author zhouhengzhe
    * @date 2021/9/4下午3:24
    * @since 
    */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "course")
public class Course {
    @TableId(value = "cid")
    private Long cid;

    @TableField(value = "cname")
    private String cname;

    @TableField(value = "user_id")
    private Long userId;

    @TableField(value = "cstatus")
    private String cstatus;
}

mapper

package com.zhz.shardingspheredemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zhz.shardingspheredemo.pojo.Course;

  /**  
    * @Description: 课程mapper数据操作层
    * 
    * @author zhouhengzhe
    * @date 2021/9/4下午3:24
    * @since 
    */
public interface CourseMapper extends BaseMapper<Course> {
}

启动类

package com.zhz.shardingspheredemo;

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

/**
 * @author mac
 */
@SpringBootApplication
@MapperScan("com.zhz.shardingspheredemo.mapper")
public class ShardingSphereDemoApplication {

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

2.3.1、分表不分库

coursedb库有两个表

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
);

2.3.1.1、配置文件

#配置数据源
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/coursedb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=root

# 要生成多少张真实表(#配置真实表分布)
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m1.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.key-generator.props.worker.id=1
#配置分表策略
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
# 通过注册与现有定义同名的定义,设置是否允许覆盖 bean 定义 默认false
spring.main.allow-bean-definition-overriding=true

解释:

  • 1、首先定义一个数据源m1,并对m1进行实际的JDBC参数配置
  • 2、spring.shardingsphere.sharding.tables.course开头的一系列属性即定义了一个名为course的逻辑表。
    • actual-data-nodes属性即定义course逻辑表的实际数据分布情况,他分布在m1.course_1和m1.course_2两个表。
    • key-generator属性配置了他的主键列以及主键生成策略。
    • ShardingJDBC默认提供了UUID和SNOWFLAKE两种分布式主键生成策略。
    • table-strategy属性即配置他的分库分表策略。分片键为cid属性。分片算法为course_$->{cid%2+1},表示按照cid模2+1的结果,然后加上前面的course__ 部分作为前缀就是他的实际表结果。注意,这个表达式计算出来的结果需要能够与实际数据分布中的一种情况对应上,否则就会报错。
    • sql.show属性表示要在日志中打印实际SQL

2.3.1.2、测试类

package com.zhz.shardingspheredemo;

import com.zhz.shardingspheredemo.mapper.CourseMapper;
import com.zhz.shardingspheredemo.pojo.Course;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingSphereDemoApplicationTests {

    @Resource
    private CourseMapper courseMapper;

    @Test
    public void testSharding() {
        for (int i = 0; i < 10; i++) {
            Course course=Course
                    .builder()
                    .cname("shardingSphere")
                    .userId((long)(1000+i))
                    .cstatus("1")
                    .build();
            courseMapper.insert(course);
        }
    }
}

2.3.1.3、运行结果

image-20210905043744405

2.3.2、奇偶分表分库

coursedb,coursedb2库都各自有两个相同的表

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
);

2.3.2.1、配置文件:

#配置数据源
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/coursedb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=root

#配置数据源
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/coursedb2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=root

# 要生成多少张真实表(#配置真实表分布)
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{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.key-generator.props.worker.id=1
#配置分表策略
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=cid
spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=m$->{cid%2+1}
#其他运行属性
spring.shardingsphere.props.sql.show=true
# 通过注册与现有定义同名的定义,设置是否允许覆盖 bean 定义 默认false
spring.main.allow-bean-definition-overriding=true

2.3.2.2、测试类

package com.zhz.shardingspheredemo;

import com.zhz.shardingspheredemo.mapper.CourseMapper;
import com.zhz.shardingspheredemo.pojo.Course;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingSphereDemoApplicationTests {

    @Resource
    private CourseMapper courseMapper;

    @Test
    public void testSharding() {
        for (int i = 0; i < 10; i++) {
            Course course=Course
                    .builder()
                    .cname("shardingSphere")
                    .userId((long)(1000+i))
                    .cstatus("1")
                    .build();
            courseMapper.insert(course);
        }
    }
}

2.3.2.3、运行结果

image-20210905171837661

image-20210905171859650

我们会发现course的course_1里面和course2里面的course_2里面有数据!!

测试查询:

 @Test
    public void testQuery(){
        QueryWrapper<Course> queryWrapper=new QueryWrapper<>();
        //成功
//        queryWrapper.eq("cid",1434444620292460546L);
        //成功
//        queryWrapper.orderByAsc("cid");
        queryWrapper.between("cid",1434444618337914881L,1434444620539924482L);
        List<Course> courses = courseMapper.selectList(queryWrapper);
        courses.forEach(System.out::println);
    }

发现不能范围查询,因为inline是根据分区键玩的!!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。