springboot+mybatisplus+sharding-jdbc分库分表

概念

什么是分库分表

当我们使用读写分离、索引、缓存后,数据库的压力还是很大的时候,这就需要使用到数据库拆分了。

分库:从单个数据库拆分成多个数据库的过程,将数据散落在多个数据库中。
分表:从单张表拆分成多张表的过程,将数据散落在多张表内。

为什么要分库分表

分库分表可以提升系统的稳定性跟负载能力,不存在单库/单表大数据。没有高并发的性能瓶颈,增加系统可用性。缺点是分库表无法join,只能通过接口方式解决,提高了系统复杂度。

Sharding-JDBC 实现分库分表

Sharding-JDBC最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名为ShardingSphere, 2020年4月16日正式成为Apache软件基金会的顶级项目,同时兼容多种数据库,通过可插拔架构,理想情况下,可以做到对业务代码无感知。

使用手册

引入依赖

 <dependency>
    <groupId>org.apache.shardingsphere</groupId>
     <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
     <version>4.1.1</version>
 </dependency>

配置分库分表规则

1:标准分片策略
2:复合分片策略
3:行表达式分片策略
4:Hint分片策略

本实例介绍了3:行表达式分片策略 和 1:标准分片策略

1:标准分片策略

/**
 * 数据库精准分片
 * @author zbm
 * @date 2024/3/1417:08
 */
public class AccurateDBShardingConfig implements PreciseShardingAlgorithm<Long> {

    /**
     *
     * @param dataSourceNames 数据源集合
     *                      在分库时值为所有分片库的集合 databaseNames
     *                      分表时为对应分片库中所有分片表的集合 tablesNames
     *
     * @param shardingValue  分片属性,
     *                       logicTableName 为逻辑表,
     *                       columnName 分片健(字段),
     *                       value 为从 SQL 中解析出的分片健的值
     * @return
     */
    @Override
    public String doSharding(Collection<String> dataSourceNames, PreciseShardingValue<Long> shardingValue) {
        for (String databaseName : dataSourceNames) {

            String value = shardingValue.getValue().hashCode()%2+"";
            //value是0,则进入0库表,1则进入1库表
            if (databaseName.endsWith(value)) {
                return databaseName;
            }

        }
        throw new IllegalArgumentException();
    }
/**
 * @author zbm
 * @date 2024/3/1417:20
 */
public class PreciseTablesShardingConfig implements PreciseShardingAlgorithm<Long> {
    @Override
    public String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> preciseShardingValue) {
        // 获取分片键的值
        Long shardingValue = preciseShardingValue.getValue();
        // 取模分表(取模都是从0到collection.size())
        long index = shardingValue.hashCode() % tableNames.size();
        // 判断逻辑表名
        String logicTableName = preciseShardingValue.getLogicTableName();
        // 物理表名
        String PhysicalTableName = logicTableName + "_" + (index);
        // 判断是否存在该表
        if (tableNames.contains(PhysicalTableName)) {
            return PhysicalTableName;
        }
        // 不存在则抛出异常
        throw new UnsupportedOperationException();

    }
}

3:行表达式分片策略

application.properties

#配置数据源的名字
server.port=8085
spring.shardingsphere.datasource.names=m0,m1

#配置第一个数据源具体内容,包含连接池,驱动,地址,用户名和密码
spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=12345678

#配置第二个数据源具体内容,包含连接池,驱动,地址,用户名和密码
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/db2?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=12345678

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

##指定查询到库的那个表
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=m$->{0..1}.product_order_$->{0..1}

##定义主键的规则
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=snowflake

##指定表分片的策略 约定cid值,奇数在
#spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=id
#spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{id % 2}

#配置文件精准分片
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.precise-algorithm-class-name=com.example.shardingjdbc.config.PreciseTablesShardingConfig

##指定数据库的分片规则 约定user_id 奇数在库2 偶数在库1
#spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=id
#spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=db$->{id % 2 + 1}

#spring.shardingsphere.sharding.tables.product_order.database-strategy.inline.sharding-column=id
#spring.shardingsphere.sharding.tables.product_order.database-strategy.inline.algorithm-expression=m$->{id % 2}
#配置文件数据库分片
spring.shardingsphere.sharding.tables.product_order.database-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.product_order.database-strategy.standard.precise-algorithm-class-name=com.example.shardingjdbc.config.AccurateDBShardingConfig

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

问题

数据倾斜问题

行表达式分片算法、复合行表达式分片算法、Hint 行表达式分片算法的取模形式的行表达式算法也会存在这个问题。比方说,我们按5库20表进行发分库分表,只有分片键是0或是5的倍数才会落到0库,但是又因为是20表,所以落到0库的数据只会分布在0或5或10或15这4个表中,导致路由到0库的数据永远不会落到除上述4个表的其他16个表中

数据倾斜问题解决

个人是不太推荐单纯的根据分片键取模分片算法的,在实际的项目中一直使用的是自定义类分片算法,实质是根据分片键的最后一位数字对数据库数取模,分片键的倒数二三位数字对表数取模。这种方式可以尽量避免数据倾斜问题,不会存在某些库表永远不会有数据的情况。

源码github:https://github.com/zbmzbm/springboot-sharding-jdbc

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值