Sharding-JDBC-自定义分片策略

代码: sharding-jdbc-study.git

背景

针对订单表,按照省份进行分片

table结构

CREATE TABLE `t_order` (
                              `order_id` bigint(20) NOT NULL COMMENT '订单id',
                              `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
                              `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
                              `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
                              PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB ;

standrad策略

建立分片表

分片表扩展province字段。

DROP TABLE IF EXISTS `t_order_bj`;
CREATE TABLE `t_order_bj` (
                              `order_id` bigint(20) NOT NULL COMMENT '订单id',
                              `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
                              `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
                              `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
                              `province` char(6) NOT NULL COMMENT '所属省份',

                              PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB ;

DROP TABLE IF EXISTS `t_order_ah`;
CREATE TABLE `t_order_ah` (
                              `order_id` bigint(20) NOT NULL COMMENT '订单id',
                              `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
                              `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
                              `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
                              `province` char(6) NOT NULL COMMENT '所属省份',
                              PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB ;

yaml配置

仅定义ah和bj两个分片

spring:
  shardingsphere:
    datasource:
      ## 定义数据源 多个以逗号分隔开
      names: m1
      ## 定义数据源 m1
      m1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: XXXX
        username: XXXXX
        password: XXXXX
    sharding:
      tables:
        t_order:
          ## 指定 t_order表的 数据分布情况,配置数据节点
          actual-data-nodes: m1.t_order_bj,m1.t_order_ah
          ## 指定t_order表的主键列,以及主键生成策略为SNOWFLAKE
          key-generator:
            column: order_id
            type: SNOWFLAKE
          ## 指定t_order的分片策略: 设置分片键和分片算法
          table-strategy:
            standard:
              sharding-column: province
              ## 指定分片算法
              precise-algorithm-class-name: cn.jhs.sharding.chap11.ProvincePreciseShardingAlgorithm

    # 打开sharding-jdbc sql输出
    props:
      sql:
        show: true

自定义分片算法

public class ProvincePreciseShardingAlgorithm implements PreciseShardingAlgorithm<String> {

    private static final ImmutableMap<String, String> MAPPINGS = ImmutableMap.<String, String>builder().put("110000", "bj").put("340000", "ah").build();

    /**
     * @param availableTargetNames 物理表 - 集合
     * @param shardingValue        分偏键盘
     * @return
     */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {
        String sharding = MAPPINGS.get(shardingValue.getValue());
        if(sharding != null) {
            for (String table : availableTargetNames) {
                if (table.endsWith(sharding)) {
                    return table;
                }
            }
        }
        throw new RuntimeException("未识别的是分偏键{" + sharding + "}");
    }
}

dao

@Mapper
@Component
public interface Order11Dao {

    @Insert("insert into t_order(price,user_id,status,province) value(#{price},#{userId},#{status},#{province})")
    int insertOrder(@Param("price") BigDecimal price, @Param("userId") Long userId,
                    @Param("status") String status,@Param("province") String province);
                    
    @Select({"<script>" +
            "select " +
            " * " +
            " from t_order t" +
            "</script>"})
    List<Map> selectAll(@Param("province") String province);


    @Select({"<script>" +
            "select " +
            " * " +
            " from t_order t" +
            " where t.province = #{province} " +
            "</script>"})
    List<Map> selectSharding(@Param("province") String province);
}

测试用例

insert
 @Test
    public void testInsertOrder() {
        for (int i = 0; i < 10; i++) {
            if( i % 2 == 0) {
                orderDao.insertOrder(new BigDecimal((i + 1) * 5), 1L, "WAIT_PAY","340000");
            }else{
                orderDao.insertOrder(new BigDecimal((i + 1) * 5), 1L, "WAIT_PAY","110000");
            }
        }
    }

结果
在这里插入图片描述

select-使用分片键
   @Order(3)
    @Test
    public void testSelectOrderbyIds2(){
        orderDao.selectSharding("340000").stream().forEach(System.out::println);
    }

sql日志
在这里插入图片描述

select-不使用分片键

虽然指定了 查询参数province但是实际执行的sql中,并没有使用该字段作为查询条件

   @Order(2)
    @Test
    public void testAll(){
        orderDao.selectAll("340000").stream().forEach(System.out::println);
    }

sql日志
全包扫描
在这里插入图片描述

Hint强制路由

上文的解决方式,需要在分片表中增加province字段,实际上该字段并无实际的业务含义(通过表名即可获取省份信息)。

Hint不再从SQL 解析中获取值,而是直接通过hintManager来指定分片键

建立分片表

分片表扩展province字段。

DROP TABLE IF EXISTS `t_order_bj`;
CREATE TABLE `t_order_bj` (
                              `order_id` bigint(20) NOT NULL COMMENT '订单id',
                              `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
                              `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
                              `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
                              PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB ;

DROP TABLE IF EXISTS `t_order_ah`;
CREATE TABLE `t_order_ah` (
                              `order_id` bigint(20) NOT NULL COMMENT '订单id',
                              `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
                              `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
                              `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
                              PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB ;

yaml配置

####...
	     table-strategy:
            hint:
              algorithm-class-name: cn.jhs.sharding.chap12.ProvinceHintShardingKeyAlgorithm

分片策略

public class ProvinceHintShardingKeyAlgorithm implements HintShardingAlgorithm<String> {


    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<String> shardingValue) {
        Collection<String> shardingCollection = shardingValue.getValues();

        List<String> result = availableTargetNames.stream().filter(table -> {
            for (String sharding : shardingCollection) {
                if (table.endsWith(sharding)) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());

        if (result.isEmpty()) {
            throw new RuntimeException("未识别的是分偏键{" + shardingCollection + "}");
        }

        return result;

    }
}

dao配置

@Mapper
@Component
public interface Order12Dao {

    @Insert("insert into t_order(price,user_id,status) value(#{price},#{userId},#{status})")
    int insertOrder(@Param("price") BigDecimal price, @Param("userId") Long userId,
                    @Param("status") String status);

    @Select({"<script>" +
            "select " +
            " * " +
            " from t_order t" +
            "</script>"})
    List<Map> selectAll();

}

单元测试

   public void testInsertOrder() {
        //清理
        HintManager.clear();
        // Hint分片策略必须要使用 HintManager工具类
        HintManager hintManager = HintManager.getInstance();

        //设置表分片逻辑
        hintManager.addTableShardingValue("t_order", "ah");

//        hintManager.addDatabaseShardingValue(); //数据库分片逻辑
//        hintManager.setMasterRouteOnly(); //在读写分离数据库中,Hint 可以强制读主库(主从复制是存在一定延时,但在业务场景中,可能更需要保证数据的实时性)
        orderDao.insertOrder(new BigDecimal(1234), 1L, "WAIT_PAY");


        //清理
        HintManager.clear();
    }

结果
在这里插入图片描述

完善AOP

public void before(){
 	 //清理
     HintManager.clear();
     // Hint分片策略必须要使用 HintManager工具类
     HintManager hintManager = HintManager.getInstance();

     //设置表分片逻辑
     hintManager.addTableShardingValue("t_order", "ah");
}


public void after(){
}


引用 https://blog.csdn.net/womenyiqilalala/article/details/105683828

常见分片策略

Sharding-JDBC中的分片策略有两个维度:

  • 数据源分片策略(DatabaseShardingStrategy):数据被分配的目标数据源
  • 表分片策略(TableShardingStrategy):数据被分配的目标表
  • 两种分片策略API完全相同,但是表分片策略是依赖于数据源分片策略的(即:先分库,然后才有分表)

在这里插入图片描述
Sharding分片策略继承自ShardingStrategy,提供了5种分片策略。

io.shardingsphere.core.routing.strategy.ShardingStrategy
   --io.shardingsphere.core.routing.strategy.standard.StandardShardingStrategy
   --io.shardingsphere.core.routing.strategy.standard.ComplexShardingStrategy
   --io.shardingsphere.core.routing.strategy.standard.InlineShardingStrategy
   --io.shardingsphere.core.routing.strategy.standard.HintShardingStrategy
   --io.shardingsphere.core.routing.strategy.standard.NoneShardingStrategy
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程简介 随着互联网的发展,软件的规模在逐渐变大,用关系型数据库如何存储和处理大规模的业务数据成为企业面临的挑战, 关系型数据库作为OLTP(联机事务处理过程)系统的首选毋庸置疑,但是关系型数据面对大规模数据的处理有其先天的不足,比如单表存储上千万数据时便会出现不同程度的处理速度缓慢问题,如何解决?分库分表技术就是为了解决由于数据量过大而导致数据库性能降低的问题,将原来独立的数据库拆分成若干数据库组成 ,将数据大表拆分成若干数据表组成,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。本课程将系统的讲解分库分表技术。 课程价值 分库分表技术是为解决关系型数据库存储和处理大规模数据的问题,主要应用于OLTP系统,它与应用于OLAP(联机分析处理)的大数据技术有不同的应用场景,本课程本着从解决生产实际问题出发,讲授分库分表技术的解决方案,包括:垂直分库、垂直分表、水平分库、水平分表、读写分离,涵盖了分库分表的各种方案,并且深入讲解Sharding-JDBC框架的原理及使用方法,通过学习本课程可以快速应用到生产实践中。 课程优势 本课程不仅讲解多种有效的分库分表的解决方案,还深入讲解了Sharding-JDBC框架的原理和使用方法,Sharding-JDBC是一套轻量级的对代码零侵入的框架,在生产中有广泛的使用。本课程从思想原理、技术框架、案例实操三个方面去学习,可以快速的将分库分表技术应用到生产实践中,解决大数据存储与处理的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值