shardingsphere 4.x(一)简介及Sharding-JDBC使用

大叔 大叔 | 544 | 2023-06-21

Apache ShardingSphere 由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的基于数据库作为存储节点的增量功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

关系型数据库当今依然占有巨大市场份额,是企业核心系统的基石,未来也难于撼动,我们更加注重在原有基础上提供增量,而非颠覆。

Sharding-JDBC

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

  • 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC;
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等;
  • 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。

660bf7b4724f401aa3ce0714b4c40e00.png

ShardingSphere-JDBC 主要做两个功能:

  • 数据分片
  • 读写分离

整合Spring Boot

项目采用Spring Boot + MybatisPlus + Sharding-JDBC +Druid 连接池

依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</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.2.8</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</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>

水平拆分

  1. 创建数据库 test_jdbc
  2. 在数据库创建两张表 test_standard_1,test_standard_2
  3. 约定规则:test_standard_2存储ID为奇数的数据,test_standard_1存入ID为偶数的数据
  4. 配置 Sharding-JDBC 分片策略,官网地址

注意一点,sharding-jdbc 版本不一样,配置也是有很大区别的,我这里是 4.0.0-RC1,大家要看 4.0的文档

建表语句
CREATE TABLE `test_standard_1` (
  `id` bigint NOT NULL,
  `name` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

application.properties配置

我见有的人说不支持 yml 格式,所以注意下

# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
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://192.168.81.104:3306/test_jdbc?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021


# 指定 standard 表分布情况,配置表在哪个数据源(数据库)里面,表名称都是什么,即 m1.standard_1 m1.standard_2
spring.shardingsphere.sharding.tables.test_standard.actual-data-nodes=m1.test_standard_$->{1..2}

# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.test_standard.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.test_standard.key-generator.type=SNOWFLAKE

# 指定分片策略 约定ID值 奇数添加到standard_2 偶数添加到standard_1
spring.shardingsphere.sharding.tables.test_standard.table-strategy.inline.sharding-column=id
# 会拿雪花ID % 服务数量 ,但是总会得到 0 | 1,所以会找 test_standard_0 或 test_standard_1,+1 解决这样的问题
spring.shardingsphere.sharding.tables.test_standard.table-strategy.inline.algorithm-expression=test_standard_$->{id % 2 + 1}

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

spring.main.allow-bean-definition-overriding=true
测试类

这里 就不写 TestStandardMapper 和 TestStandard 实体类了

@SpringBootTest
class ShardingJdbcApplicationTests {

    @Resource
    public TestStandardMapper testStandardMapper;

    @Test
    void insert() {
        for(int i=0;i<10;i++) {
            TestStandard testStandard = new TestStandard();
            testStandard.setName("张三"+i);
            testStandardMapper.insert(testStandard);
        }
    }

    @Test
    void selectByID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 你的ID是什么类型这里就一定要是什么类型,否则会报错
        wrapper.eq("id",1469257890131025922L);
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }

    @Test
    void selectByName() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 查询别的字段回去两个表都查
        wrapper.eq("name","张三3");
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }

    @Test
    void selectInID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会对所有ID值进行取余得到具体去哪个表查
        wrapper.in("id",1469263053449306114L,1469263055173165058L);
        List<TestStandard> testStandard = testStandardMapper.selectList(wrapper);
        System.out.println(testStandard);
    }
}

水平分库并水平分表

  1. 创建两个数据库 test_jdbc1,test_jdbc2
  2. 在这两个数据库都创建 test_standard_1,test_standard_2两张表
  3. 约定规则:
    3.1. user_id 为偶数则添加到 test_jdbc1 库中,为奇数添加到 test_jdbc2 库中
    3.2. id 为偶数添加到 test_standard_1 表,为奇数添加到 test_standard_2 表
表结构
CREATE TABLE `test_standard_1` (
  `id` BIGINT NOT NULL,
  `user_id` BIGINT DEFAULT NULL,
  `name` VARCHAR(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
配置
# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
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://192.168.81.104:3306/test_jdbc1?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021

# 配置数据源的驱动\连接池\账号密码等
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://192.168.81.104:3306/test_jdbc2?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=dev_fqr
spring.shardingsphere.datasource.m2.password=Dev@fqr2021


# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.test_standard.actual-data-nodes=m$->{1..2}.test_standard_$->{1..2}

# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.test_standard.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.test_standard.key-generator.type=SNOWFLAKE

# 指定表分片策略 约定ID值 奇数添加到standard_1 偶数添加到standard_2
spring.shardingsphere.sharding.tables.test_standard.table-strategy.inline.sharding-column=id
# 会拿雪花ID % 服务数量 ,但是总会得到 0 | 1,所以会找 test_standard_0 或 test_standard_1
spring.shardingsphere.sharding.tables.test_standard.table-strategy.inline.algorithm-expression=test_standard_$->{id % 2 + 1}

# 指定数据库分片策略,根据user_id做判断,偶数添加到m1,奇数添加到m2,default-database-strategy=默认所有表都按这样的规则
#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.test_standard.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.test_standard.database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}

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

spring.main.allow-bean-definition-overriding=true
测试
@SpringBootTest
class ShardingJdbcApplicationTests {

    @Resource
    public TestStandardMapper testStandardMapper;

    @Test
    void insert() {
        for(int i=0;i<10;i++) {
            TestStandard testStandard = new TestStandard();
            testStandard.setName("张三"+i);
            testStandard.setUserId(Math.round(Math.random()*100));
            testStandardMapper.insert(testStandard);
        }
    }

    @Test
    void selectByID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会查询两个数据源并直接命中到跟ID取余的表,找到数据
        wrapper.eq("id",1470229287665823746L);
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }

    @Test
    void selectByUserID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会查询跟user_id取余的库,并把库中要找的表都查出来,找数据在哪里
        wrapper.eq("user_id",66);
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }


    @Test
    void selectByName() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会查询两个数据源,并且查询所有的表,找到张三3这个用户
        wrapper.eq("name","张三3");
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }

    @Test
    void selectInID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会对所有ID值进行取余得到具体去哪个表查
        wrapper.in("id",1469263053449306114L,1469263055173165058L);
        List<TestStandard> testStandard = testStandardMapper.selectList(wrapper);
        System.out.println(testStandard);
    }

}

垂直分库

  1. 创建两个不同的数据库 user_db,order_db
  2. 在user_db库里面创建 user_info,order_db 库里面创建order_info表

垂直分库一般适用于微服务,一个业务连一个库,我这里有点多数据源的意思。

配置
# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
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://192.168.81.104:3306/user_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021

# 配置数据源的驱动\连接池\账号密码等
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://192.168.81.104:3306/order_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=dev_fqr
spring.shardingsphere.datasource.m2.password=Dev@fqr2021

# 针对 user_db 库的某些表进行特殊处理
# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.user_info.actual-data-nodes=m$->{1}.user_info
# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.user_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.user_info.key-generator.type=SNOWFLAKE
# 指定表分片策略 约定ID值
spring.shardingsphere.sharding.tables.user_info.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.user_info.table-strategy.inline.algorithm-expression=user_info

# 针对order_db 库的某些表进行特殊处理
# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.order_info.actual-data-nodes=m$->{2}.order_info
# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.order_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.order_info.key-generator.type=SNOWFLAKE
# 指定表分片策略 约定ID值
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.algorithm-expression=order_info

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

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

注意,这里记得要给实体类上加 @Table 注明实体类与哪张表有关系,否则插入报错

@SpringBootTest
class ShardingJdbcApplicationTests {

    @Resource
    public UserInfoMapper userInfoMapper;
    @Resource
    public OrderInfoMapper orderInfoMapper;

    @Test
    void insert() {
        for(int i=0;i<10;i++) {
            UserInfo userInfo = new UserInfo();
            userInfo.setName("用户"+i);
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setName("用户"+i);
            orderInfoMapper.insert(orderInfo);
            userInfoMapper.insert(userInfo);
        }
    }

}

全局表(公共表)

  1. 存储固定数据的表,表数据很少发生变化,查询时候经常进行关联
  2. 在每个数据库中创建出相同结构的公共表
  3. 公共表的数据要添加都添加,要删除都删除
  4. 在 user_db,order_db中创建公共表,public_info
配置
# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
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://192.168.81.104:3306/user_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021

# 配置数据源的驱动\连接池\账号密码等
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://192.168.81.104:3306/order_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=dev_fqr
spring.shardingsphere.datasource.m2.password=Dev@fqr2021

# 针对 user_db 库的某些表进行特殊处理
# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.user_info.actual-data-nodes=m$->{1}.user_info
# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.user_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.user_info.key-generator.type=SNOWFLAKE
# 指定表分片策略 约定ID值
spring.shardingsphere.sharding.tables.user_info.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.user_info.table-strategy.inline.algorithm-expression=user_info

# 针对order_db 库的某些表进行特殊处理
# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.order_info.actual-data-nodes=m$->{2}.order_info
# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.order_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.order_info.key-generator.type=SNOWFLAKE
# 指定表分片策略 约定ID值
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.algorithm-expression=order_info


# 配置公共表
spring.shardingsphere.sharding.broadcast-tables=public_info
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.public_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.public_info.key-generator.type=SNOWFLAKE


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

spring.main.allow-bean-definition-overriding=true
测试
@SpringBootTest
class ShardingJdbcApplicationTests {

    @Resource
    public PublicInfoMapper publicInfoMapper;

    @Test
    void insert() {
        // 会往不同数据源相同表插入数据
        for(int i=0;i<10;i++) {
            PublicInfo publicInfo = new PublicInfo();
            publicInfo.setName("公共数据"+i);
            publicInfo.setForeignKey((long)i);
            publicInfoMapper.insert(publicInfo);
        }
    }

    @Test
    void select() {
        QueryWrapper<PublicInfo> wrapper = new QueryWrapper<>();
        // 会随机从m1,m2 中读取数据
        for(int i=0;i<10;i++) {
            wrapper.eq("id", 1470262655996567553L);
            PublicInfo publicInfo = publicInfoMapper.selectOne(wrapper);
            System.out.println(publicInfo);
        }
    }
    
}

读写分离配置

Sharding-JDBC 会根据语义的不同,来区分主从的读写分离,如 update、insert 等走主库,select 走从库

# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
spring.shardingsphere.datasource.names=m1,s1

# 配置数据源的驱动\连接池\账号密码等
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://192.168.81.104:3306/user_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.s1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.s1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.s1.url=jdbc:mysql://192.168.81.104:3306/user_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.s1.username=dev_fqr
spring.shardingsphere.datasource.s1.password=Dev@fqr2021


# 主从主要配置,多个从可以以','分割,ds0 是一个逻辑库,统一主从主体信息
spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m1
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=s1

# 指定 表的分布情况
spring.shardingsphere.sharding.tables.user_info.actual-data-nodes=ds0.user_info


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

spring.main.allow-bean-definition-overriding=true
推荐指数:

真诚点赞 诚不我欺~

shardingsphere 4.x(一)简介及Sharding-JDBC使用

点赞 收藏 评论

关于作者

大叔
大叔

这个人很懒~

等级 LV1

粉丝 0

获赞 0

经验 13