飞道的博客

springboot结合sharding-jdbc4.0版本实现分库分表(整合druid+mybatis)

629人阅读  评论(0)

数据库优化

优化策略

  1. 表结构的优化,包括字段,类型,长度等
  2. 进行索引等数据库级别的优化
  3. 业务需求场景层面的优化调整

在以上几种手段都用了之后再进行分库分表的操作.一般不推荐上来就分库分表.除非能够预测到数据量的级别.

什么时候需要分库分库

Mysql数据库单表数据量在1千万以下时可以保证性能超过则需要更多的维护优化成本.
在数据量涨幅预期过快时,需要提前进行分库分表.

数据库分表的几种方案

mycat之类的中间件

mycat属于中间件的实现方式,应用直接连接mycat,然后由mycat去选择具体的库和表.

sharding-jdbc之类的代理层

sharding-jdbc具体使用方式

先在pom.xml中引入依赖

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

这里用的是sharding-jdbc-spring-boot-starter
需要注意的是,此时druid不能用spring-boot-starter版本的,需要用正常的包:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.22</version>
</dependency>

不然启动会报错找不到url

在配置文件中添加数据分片相关的配置

spring:
	shardingsphere:
	    datasource:
	      names: ds0
	      ds0:
	        type: com.alibaba.druid.pool.DruidDataSource
	        url: jdbc:mysql://127.0.01:3306/demo
	        username: root
	        password: '123456'
	    sharding:
	      tables:
	        userorder:
	          actual-data-nodes: ds0.t_order$->{0..1}
	          table-strategy:
	            inline:
	              sharding-column: orderid
	              algorithm-expression: t_order$->{orderid % 2}
	      defaultDataSourceName: ds0
	    props:
	      sql.show: true

这里type填数据库连接池的类名.
具体其他配置项,参考官方文档

自定义分片策略

首先新建一个类,实现对应的分片方法:

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;


public class ShardingTest implements PreciseShardingAlgorithm<String>, RangeShardingAlgorithm<String> {
    /**
     * in/= 判断标准
     *
     * @param collection
     * @param preciseShardingValue
     * @return
     */
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
        Date time = DateUtil.parse(preciseShardingValue.getValue(), "yyyy-MM-dd HH:mm:ss");
        String logicTableName = preciseShardingValue.getLogicTableName();
        int year = DateUtil.year(time);
        // 定义表名
        String tableName = logicTableName + year;
        for (String name : collection) {
            if (tableName.equals(name)) {
                return tableName;
            }
        }
        throw new IllegalArgumentException();
    }

    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<String> rangeShardingValue) {
        System.out.println(rangeShardingValue.getValueRange());
        Range<String> valueRange = rangeShardingValue.getValueRange();
        Date right = null;
        Date left = null;
        // 如果有固定范围则取
        if (valueRange.hasLowerBound()) {
            String lowerEndpoint = valueRange.upperEndpoint();
            String yearMonth = lowerEndpoint.substring(0, 7);
            left = DateUtil.parse(yearMonth, "yyyy-MM");
        }
        if (valueRange.hasUpperBound()) {
            String upperEndpoint = valueRange.upperEndpoint();
            String yearMonth = upperEndpoint.substring(0, 7);
            right = DateUtil.parse(yearMonth, "yyyy-MM");
        }
        Range<Date> range;
        if (left == null && right != null) {
            range = Range.upTo(right, valueRange.upperBoundType());
        } else if (right == null && left != null) {
            range = Range.downTo(left, valueRange.lowerBoundType());
        } else {
            range = Range.range(right, valueRange.lowerBoundType(), left, valueRange.upperBoundType());
        }
        ArrayList<String> list = new ArrayList<>();
        for (String tableOriginName : collection) {
            String[] userorders = tableOriginName.split("userorder");
            String tableTime = userorders[1];
            DateTime time = DateUtil.parse(tableTime, "yyyy");
            if (range.contains(time)) {
                list.add(tableOriginName);
            }
        }
        return list;
    }
}

然后在配置文件中指定类名:

spring:
	shardingsphere:
	    datasource:
	      ...
	    sharding:
	      tables:
	        userorder:
	          actual-data-nodes: ds0.t_order$->{2017..2020}
	          table-strategy:
	            standard:
	              shardingColumn: orderTime #分片列名称
	              preciseAlgorithmClassName: com.demo.common.ShardingTest #精确分片算法类名称,用于=和IN。。该类需实现PreciseShardingAlgorithm接口并提供无参数的构造器
	              rangeAlgorithmClassName: com.demo.common.ShardingTest #范围分片算法类名称,用于BETWEEN,可选。。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器
	...

分库分表策略

切分策略大体可以分为垂直切分和水平切分
按分库来说
垂直切分的例子:用户库,商品库,订单库…
水平分库的例子:按用户id的奇偶,按商品的类型,按订单的时间(月份)
按分表来说
用户表,垂直切分:用户基本信息,用户附加信息,用户认证信息
用户表水平切分:按用户id的奇偶,按用户地区等


转载:https://blog.csdn.net/u014705309/article/details/105733517
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场