sharding-jdbc分片方式介绍

sharding-jdbc实现数据分片有4种策略:

  • inline模式

    • 使用最简单,开发成本比较低;

    • 只能使用单个字段作为分片键;

    • 基于行表达式定义分片规则;

通过groovy表达式来表示分库分表的策略;
db0
  ├── t_order0
  └── t_order1
db1
  ├── t_order0
  └── t_order1
  表达式:db${0..1}.t_order${0..1}
           t_order${orderId % 2} 

  • standard标准分片模式

    • 用户可通过代码自定义复杂的分片策略;

    • 同样只能使用单个字段作为分片键;

  • complex复合分片模式

    • 用于多分片键的复合分片策略(多片键)

  • Hint强制分片模式

    • 不指定片键,通过代码动态指定路由规则

    • 强制分片策略(强制路由)

基于inline模式实现水平分表

 order_db_1
  ├── t_order_1
  └── t_order_2

#创建数据库
CREATE DATABASE `order_db_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
#建表
USE order_db_1;
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
    `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 CHARACTER
SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `t_order_2`;
CREATE TABLE `t_order_2` (
    `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 CHARACTER
SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

工程集成sharding-jdbc

<dependencies>
  <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
  </dependency>
  <!--引入sharding依赖-->
  <dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.0.0-RC1</version>
  </dependency>

  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
  </dependency>
</dependencies>

 1) 主配置 定义sharding相关配置

#下面这些内容是为了让MyBatis映射
#指定Mybatis的Mapper文件
mybatis.mapper-locations=classpath:mappers/*xml
#指定Mybatis的实体目录
mybatis.type-aliases-package=com.itheima.sharding.entity
## 数据库驱动:
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
## 数据库连接地址
#spring.datasource.url=jdbc:mysql://192.168.175.129:3306/order_db_1?serverTimezone=Asia/Shanghai&useSSL=false
## 数据库用户名&密码:
#spring.datasource.username=root
#spring.datasource.password=123456

#spring.profiles.active=test1
spring.profiles.active=test8

2) 环境application-test1.properties配置  

#1.配置数据源
#数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1
#数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.175.129:3306/order_db_1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds1.username=root
#数据库密码
spring.shardingsphere.datasource.ds1.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=


#2.配置指定表的数据结点
#由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持inline表达式。
# 缺省表示使用已知数据源与逻辑表名称生成数据节点,用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)或只分库不分表且所有库的表结构完全一致的情况
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds1.t_order_${1..2}
#3.指定库的分片策略
#分片列名称
#spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.inline.sharding-column=
##分片算法行表达式,需符合groovy语法
#spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.inline.algorithm-expression=

#4.指定表的分片策略根据分片条件找到对应真实表
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id

spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_${order_id % 2 +1}





 3) 定义mapper接口和xml

package com.itheima.shardingjdbc.mapper;

import com.itheima.shardingjdbc.pojo.TOrder;
import org.apache.ibatis.annotations.Mapper;

/**
 * @Entity com.itheima.shardingjdbc.pojo.TOrder
 */
@Mapper
public interface TOrderMapper {

    int deleteByPrimaryKey(Long id);

    int insert(TOrder record);

    int insertSelective(TOrder record);

    TOrder selectByPrimaryKey(Long id);

    int updateByPrimaryKeySelective(TOrder record);

    int updateByPrimaryKey(TOrder record);

}

定义与接口绑定的xml:  

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.shardingjdbc.mapper.TOrderMapper">

    <resultMap id="BaseResultMap" type="com.itheima.shardingjdbc.pojo.TOrder">
            <id property="orderId" column="order_id" jdbcType="BIGINT"/>
            <result property="price" column="price" jdbcType="DECIMAL"/>
            <result property="userId" column="user_id" jdbcType="BIGINT"/>
            <result property="status" column="status" jdbcType="VARCHAR"/>
    </resultMap>

    <sql id="Base_Column_List">
        order_id,price,user_id,
        status
    </sql>

    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List" />
        from t_order
        where  order_id = #{orderId,jdbcType=BIGINT} 
    </select>

    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
        delete from t_order
        where  order_id = #{orderId,jdbcType=BIGINT} 
    </delete>
    <insert id="insert" parameterType="com.itheima.shardingjdbc.pojo.TOrder">
        insert into t_order
        ( order_id,price,user_id
        ,status)
        values (#{orderId,jdbcType=BIGINT},#{price,jdbcType=DECIMAL},#{userId,jdbcType=BIGINT}
        ,#{status,jdbcType=VARCHAR})
    </insert>
    <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.itheima.shardingjdbc.pojo.TOrder" useGeneratedKeys="true">
        insert into t_order
        <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="orderId != null">orderId,</if>
                <if test="price != null">price,</if>
                <if test="userId != null">userId,</if>
                <if test="status != null">status,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="orderId != null">order_id = #{orderId,jdbcType=BIGINT},</if>
                <if test="price != null">price = #{price,jdbcType=DECIMAL},</if>
                <if test="userId != null">user_id = #{userId,jdbcType=BIGINT},</if>
                <if test="status != null">status = #{status,jdbcType=VARCHAR},</if>
        </trim>
    </insert>
    <update id="updateByPrimaryKeySelective" parameterType="com.itheima.shardingjdbc.pojo.TOrder">
        update t_order
        <set>
                <if test="price != null">
                    price = #{price,jdbcType=DECIMAL},
                </if>
                <if test="userId != null">
                    user_id = #{userId,jdbcType=BIGINT},
                </if>
                <if test="status != null">
                    status = #{status,jdbcType=VARCHAR},
                </if>
        </set>
        where   order_id = #{orderId,jdbcType=BIGINT} 
    </update>
    <update id="updateByPrimaryKey" parameterType="com.itheima.shardingjdbc.pojo.TOrder">
        update t_order
        set 
            price =  #{price,jdbcType=DECIMAL},
            user_id =  #{userId,jdbcType=BIGINT},
            status =  #{status,jdbcType=VARCHAR}
        where   order_id = #{orderId,jdbcType=BIGINT} 
    </update>
</mapper>

 注意:xml中使用的逻辑表t_order,而不是t_order1、t_order2

 4) 测试

@SpringBootTest
public class TestAll {

    @Autowired
    private TOrderMapper tOrderMapper;
    @Test
   public void test1() {
        int orderId=0;
        Random random = new Random();
        for (int i = 0; i < 20; i++) {
            //保证随机生成奇数或者偶数
            orderId+=random.nextInt(2)+1;
            TOrder order = TOrder.builder().orderId(Long.valueOf(orderId))
                    .userId(Long.valueOf(i))
                    .status("1")
                    .price(new BigDecimal(300))
                    .build();
            tOrderMapper.insert(order);
        }
    }
}

sharding-jdbc广播表

广播表介绍

  • 广播表属于数据库中数据量较小和变动较少,且存在高频联合查询的表,比如:数据字典表等属于此广播表。

  • 可以将这类表在每个数据库都保存一份,所有更新操作都同时发送到所有分库执行。

order_db_1
  ├── t_order_1
  └── t_order_2
  └── t_dict
order_db_2
  ├── t_order_1
  └── t_order_2  
  └── t_dict   

#在数据库 user_db、order_db_1、order_db_2中均要建表
CREATE TABLE `t_dict` (
 `dict_id` BIGINT (20) NOT NULL COMMENT '字典id',
 `type` VARCHAR (50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典类型',
 `code` VARCHAR (50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典编码',
 `value` VARCHAR (50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典值',
 PRIMARY KEY (`dict_id`) USING BTREE
) ENGINE = INNODB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

将配置表更改

#1.配置数据源
#数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1,ds2
#数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.175.129:3306/order_db_1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds1.username=root
#数据库密码
spring.shardingsphere.datasource.ds1.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=


#数据库连接池类名称
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://192.168.175.129:3306/order_db_2?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds2.username=root
#数据库密码
spring.shardingsphere.datasource.ds2.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=
#----------------------------------------------------------------------------------------------------------------

#2.配置指定表的数据结点
#由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持inline表达式。
# 缺省表示使用已知数据源与逻辑表名称生成数据节点,用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)或只分库不分表且所有库的表结构完全一致的情况
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds${1..2}.t_order_${1..2}

#----------------------------------------------------------------------------------------------------------------
#3.指定库的分片策略
#分片列名称   使用uer_id 防止数据倾斜(如果是order_id 那只会有两个表有数据)
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column=user_id
#分片算法行表达式,需符合groovy语法
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression=ds${user_id%2+1}
#----------------------------------------------------------------------------------------------------------------
#4.指定表的分片策略根据分片条件找到对应真实表
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id

spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_${order_id % 2 +1}
#----------------------------------------------------------------------------------------------------------------
#是否开启SQL显示
spring.shardingsphere.props.sql.show=true

#----------------------------------------------------------------------------------------------------------------
# 指定t_dict为公共表,多个公共表以逗号间隔
spring.shardingsphere.sharding.broadcast‐tables=t_dict



测试广播表

    @Autowired
    private TDictMapper tDictMapper;
    
	@Test
    public void commonTable(){
        TDict build = TDict.builder().dictId(1l).code("666").type("1").value("888")
                .build();
        tDictMapper.insert(build);
    }

基于inline模式实现垂直分库

表结构

order_db_1
  ├── t_order_1
  └── t_order_2
  └── t_dict
order_db_2
  ├── t_order_1
  └── t_order_2  
  └── t_dict  
user_db
  └── t_user 

#创建数据库
CREATE DATABASE `user_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
#建表
USE user_db;
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
 `user_id` BIGINT (20) NOT NULL COMMENT '用户id',
 `fullname` VARCHAR (255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户姓名',
 `user_type` CHAR (1) DEFAULT NULL COMMENT '用户类型',
 PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = INNODB CHARACTER
SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

 将配置表更改

#1.配置数据源
#数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1,ds2,udb
#数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.175.129:3306/order_db_1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds1.username=root
#数据库密码
spring.shardingsphere.datasource.ds1.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=


#数据库连接池类名称
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://192.168.175.129:3306/order_db_2?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds2.username=root
#数据库密码
spring.shardingsphere.datasource.ds2.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=

#数据库连接池类名称
spring.shardingsphere.datasource.udb.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.udb.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.udb.url=jdbc:mysql://192.168.175.129:3306/user_db?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.udb.username=root
#数据库密码
spring.shardingsphere.datasource.udb.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=
#----------------------------------------------------------------------------------------------------------------

#2.配置指定表的数据结点
#由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持inline表达式。
# 缺省表示使用已知数据源与逻辑表名称生成数据节点,用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)或只分库不分表且所有库的表结构完全一致的情况
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds${1..2}.t_order_${1..2}
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=udb.t_user
#----------------------------------------------------------------------------------------------------------------
#3.指定库的分片策略
#分片列名称   使用uer_id 防止数据倾斜(如果是order_id 那只会有两个表有数据)
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column=user_id
#分片算法行表达式,需符合groovy语法
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression=ds${user_id%2+1}
#----------------------------------------------------------------------------------------------------------------
#4.指定表的分片策略根据分片条件找到对应真实表
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id

spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_${order_id % 2 +1}
#----------------------------------------------------------------------------------------------------------------
#是否开启SQL显示
spring.shardingsphere.props.sql.show=true

#----------------------------------------------------------------------------------------------------------------
# 指定t_dict为公共表,多个公共表以逗号间隔
spring.shardingsphere.sharding.broadcast‐tables=t_dict



测试

    @Test
    public void test04(){
        TUser user = TUser.builder().userId(133l).userType("1")
                .fullname("laozhang").build();
        tUserMapper.insert(user);
    }

默认数据源模式

如果没有配置分片策略,则可指定默认访问的数据源,也就是说只需指定数据源,无需指定数据节点、库和表的分片策略也无需执行;

如果在进行相关操作时,发现逻辑表没有对应的数据节点、库表的分片配置,则走默认指定的数据源;

-- 构建数据
create database default_db character set utf8;
use default_db;
-- 构建表
create table tb_log (
    id bigint primary key ,
    info varchar(30)
);
#1.配置数据源
#数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=defdb
#数据库连接池类名称
spring.shardingsphere.datasource.defdb.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.defdb.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.defdb.url=jdbc:mysql://192.168.175.129:3306/default_db?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.defdb.username=root
#数据库密码
spring.shardingsphere.datasource.defdb.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=


#配置默认数据源 当大量的表值存在单个库中 且库内没有水平分表处理 可使用默认数据源
#未配置分片规则的表将通过默认数据源定位
spring.shardingsphere.sharding.default-data-source-name=defdb


 测试

	/**
     * 测试默认数据源
     *  对于没有做分片处理的操作,则会直接访问默认数据源处理
     */
    @Test
    public void test5(){
        TbLog log = TbLog.builder().id(1l).info("这是一个测试").build();
        tbLogMapper.insert(log);
    }

inline模式小结

  • 优点:

    • 配置简单,开发成本低;

    • 便于理解和维护;

  • 缺点:

    • 复杂的分片策略支持不友好;

    • 对范围查询支持不太友好,动辄全节点查询,查询效率低下;

Standard模式实现分库分表

标准模式分片API介绍

# 用于单分片键的标准分片场景
sharding.jdbc.config.sharding.tables.<logic-table-name>.database-strategy.standard.sharding-column= # 分片列名称
sharding.jdbc.config.sharding.tables.<logic-table-name>.database-strategy.standard.precise-algorithm-class-name= # 精确分片算法类名称,用于 = 和 IN。该类需实现 PreciseShardingAlgorithm 接口并提供无参数的构造器
sharding.jdbc.config.sharding.tables.<logic-table-name>.database-strategy.standard.range-algorithm-class-name= # 范围分片算法类名称,用于 BETWEEN,可选。该类需实现 RangeShardingAlgorithm 接口并提供无参数的构造器

PreciseShardingAlgorithm :精准查询库或者表(sql使用使用了= 、in)
RangeShardingAlgorithm :范围查询库或者表 (between and 、 > 、 <)
所以,使用sharding-jdbc时尽量让分片键去查询,且遵循使用规范;

标准分片模式实现

定义标准分库策略
package com.itheima.sharding.alg;

import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

import java.util.Collection;
import java.util.Optional;

/**
 * ClassName: MyPreciseShardingAlgorithmDb
 * Package: com.itheima.sharding.alg
 * Description:
 *
 * @Author R
 * @Create 2024/2/10 14:23
 * @Version 1.0
 */
public class MyPreciseShardingAlgorithmDb implements PreciseShardingAlgorithm<Long> {
    /**
     *
     * @param dsNames  所有数据源的名称集合
     * @param shardingValue 片键信息的封装
     * @return 当前数据库查询名称的数据库集合
     */
    @Override
    public String doSharding(Collection<String> dsNames, PreciseShardingValue<Long> shardingValue) {
        //获取数据库的分片键名称:user_id
        String dbColumnName = shardingValue.getColumnName();
        //获取此时查询时的片键值
        Long value = shardingValue.getValue();
        //获取逻辑表名称 t_user
        String logicTableName = shardingValue.getLogicTableName();
        Optional<String> result = dsNames.stream().filter(dbName -> dbName.endsWith((value % 2 + 1) + "")).findFirst();
        if(result.isPresent()){
            return result.get();
        }
        return null;
    }
}
package com.itheima.sharding.alg;

import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

import java.util.Collection;

/**
 * ClassName: MyRangeShardingAlgorithmDb
 * Package: com.itheima.sharding.alg
 * Description:
 *
 * @Author R
 * @Create 2024/2/10 14:30
 * @Version 1.0
 */
public class MyRangeShardingAlgorithmDb implements RangeShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> dsNames, RangeShardingValue<Long> shardingValue) {
        //获取分片键名称
        String columnName = shardingValue.getColumnName();
        //获取逻辑表
        String logicTableName = shardingValue.getLogicTableName();
        //对范围数据的封装
        Range<Long> valueRange = shardingValue.getValueRange();
        //判断是否有范围查询的起始值
        if (valueRange.hasLowerBound()) {
            //获取起始值
            Long start = valueRange.lowerEndpoint();//10
        }
        //判断是否有上限值
        if (valueRange.hasUpperBound()) {
            Long end = valueRange.upperEndpoint();
        }
        return dsNames;
    }
}

 配置标准分库:

#1.配置数据源
#数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1,ds2
#数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.175.129:3306/order_db_1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds1.username=root
#数据库密码
spring.shardingsphere.datasource.ds1.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=


#数据库连接池类名称
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://192.168.175.129:3306/order_db_2?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds2.username=root
#数据库密码
spring.shardingsphere.datasource.ds2.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=
#-----------------------------------------------------------------------------------------------------------
# 配置数据节点:datanode,数据源.表 t_order是逻辑表,属于t_order_1和t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds${1..2}.t_order_${1..2}

#-----------------------------------------------------------------------------------------------------------
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.sharding-column=user_id
#精确分片算法类名称,用于=和IN。该类需实现PreciseShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.precise-algorithm-class-name=com.itheima.sharding.alg.MyPreciseShardingAlgorithmDb
#范围分片算法类名称,用于BETWEEN,可选。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.range-algorithm-class-name=com.itheima.sharding.alg.MyRangeShardingAlgorithmDb

#-----------------------------------------------------------------------------------------------------------
#分片列名称
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_${order_id % 2 +1}
#-----------------------------------------------------------------------------------------------------------

# 是否开启 SQL 显示,默认值: false
spring.shardingsphere.props.sql.show=true


    /**
     * @Description 测试数据库标准精准查询=
     */
    @Test
    public void test2(){
        List<TOrder> tOrder = tOrderMapper.findByUserId(18l);
        System.out.println(tOrder);
    }

    /**
     * @Description 测试标准查询:范围匹配 between
     */
    @Test
    public void test3(){
        List<TOrder> tOrder = tOrderMapper.findByUserIdBetween(18l,70l);
        System.out.println(tOrder);
    }
定义标准分库策略集合
package com.itheima.sharding.alg;

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.Arrays;
import java.util.Collection;

/**
 * ClassName: Common4Tb
 * Package: com.itheima.sharding.alg
 * Description:
 *
 * @Author R
 * @Create 2024/2/10 14:44
 * @Version 1.0
 */
public class Common4Tb implements PreciseShardingAlgorithm<Long>, RangeShardingAlgorithm<Long> {
    @Override
    public String doSharding(Collection<String> dsNames, PreciseShardingValue<Long> shardingValue) {
        //获取数据库分片的字段名称 user_id = in
        String columnName = shardingValue.getColumnName();
        //获取逻辑表名称
        String logicTableName = shardingValue.getLogicTableName();
        //获取片键对应的值 select * from t_order where user_id=10,这里的value就等于10
        Long value = shardingValue.getValue();
        //一般是根据片键值获取对应的数据源,并返回
        String sufix=String.valueOf(value % 2 +1);
        String dsName = dsNames.stream().filter(ds -> ds.endsWith(sufix)).findFirst().get();
        return dsName;
    }

    @Override
    public Collection<String> doSharding(Collection<String> dsNames, RangeShardingValue<Long> shardingValue) {
        //获取分片字段
        String columnName = shardingValue.getColumnName();
        //获取逻辑表
        String logicTableName = shardingValue.getLogicTableName();
        //获取范围数据
        Range<Long> valueRange = shardingValue.getValueRange();
        //select * from t_order where user_id between 1 and 20;
        //判断是否有上限值
        if (valueRange.hasUpperBound()) {
            //获取上限值 20
            Long uppper = valueRange.upperEndpoint();
            System.out.println(uppper);
        }
        if (valueRange.hasLowerBound()){
            Long lower = valueRange.lowerEndpoint();
            System.out.println(lower);
        }
        return dsNames;
    }
}

#1.配置数据源
#数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1,ds2
#数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.175.129:3306/order_db_1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds1.username=root
#数据库密码
spring.shardingsphere.datasource.ds1.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=


#数据库连接池类名称
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://192.168.175.129:3306/order_db_2?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds2.username=root
#数据库密码
spring.shardingsphere.datasource.ds2.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=
#-----------------------------------------------------------------------------------------------------------
# 配置数据节点:datanode,数据源.表 t_order是逻辑表,属于t_order_1和t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds${1..2}.t_order_${1..2}

#抽取变量
common.shard4db=com.itheima.sharding.alg.Common4Tb

#-----------------------------------------------------------------------------------------------------------
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.sharding-column=user_id
#精确分片算法类名称,用于=和IN。该类需实现PreciseShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.precise-algorithm-class-name=${common.shard4db}
#范围分片算法类名称,用于BETWEEN,可选。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.range-algorithm-class-name=${common.shard4db}

#-----------------------------------------------------------------------------------------------------------
#分片列名称
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_${order_id % 2 +1}
#-----------------------------------------------------------------------------------------------------------

# 是否开启 SQL 显示,默认值: false
spring.shardingsphere.props.sql.show=true


定义标准分表策略
package com.itheima.sharding.alg;

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.Arrays;
import java.util.Collection;

/**
 * @author by itheima
 * @Date 2022/6/11
 * @Description 定义精准查询表的算法类 接口中的泛型与数据库的片键类型一致
 * 保证片键中使用= in
 */
public class CommonAlgorithm4Tb implements PreciseShardingAlgorithm<Long>, RangeShardingAlgorithm<Long> {

    /**
     * 定义精准匹配表的方法
     * @param tbNames 所有配置的物理表的集合t_order_${1..2} 包含t_order_1 t_order_2封装到该集合下
     *                说白了就是sharinding把所有的数据源都给你,然后让你根据片键值选择
     * @param shardingValue 封装分片相关信息
     * @return 返回匹配的数据源
     */
    @Override
    public String doSharding(Collection<String> tbNames, PreciseShardingValue<Long> shardingValue) {
        //获取数据库分片的字段名称 user_id = in
        String columnName = shardingValue.getColumnName();
        //获取逻辑表名称
        String logicTableName = shardingValue.getLogicTableName();
        //获取片键对应的值 select * from t_order where order_id=10,这里的value就等于10
        Long value = shardingValue.getValue();
        //一般是根据片键值获取对应的数据源,并返回
        String sufix=String.valueOf(value % 2 +1);
        String dsName = tbNames.stream().filter(ds -> ds.endsWith(sufix)).findFirst().get();
        return dsName;
    }

    /**
     * @param tbNames 数据源集合
     * @param shardingValue 范围查询信息封装
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> tbNames, RangeShardingValue<Long> shardingValue) {
        //获取分片字段
        String columnName = shardingValue.getColumnName();
        //获取逻辑表
        String logicTableName = shardingValue.getLogicTableName();
        //获取范围数据
        Range<Long> valueRange = shardingValue.getValueRange();
        //select * from t_order where user_id between 1 and 20;
        //判断是否有上限值
        if (valueRange.hasUpperBound()) {
            //获取上限值 20
            Long uppper = valueRange.upperEndpoint();
            System.out.println(uppper);
        }
        if (valueRange.hasLowerBound()){
            Long lower = valueRange.lowerEndpoint();
            System.out.println(lower);
        }
        //理论上要根据上限值和下限值获取满足条件的数据源集合
        return Arrays.asList("t_order_1","t_order_2");
    }
}

#1.配置数据源
#数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1,ds2
#数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.175.129:3306/order_db_1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds1.username=root
#数据库密码
spring.shardingsphere.datasource.ds1.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=


#数据库连接池类名称
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
#数据库url连接
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://192.168.175.129:3306/order_db_2?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
#数据库用户名
spring.shardingsphere.datasource.ds2.username=root
#数据库密码
spring.shardingsphere.datasource.ds2.password=123456
#数据库连接池的其它属性
#spring.shardingsphere.datasource.<data-source-name>.xxx=
#-----------------------------------------------------------------------------------------------------------
# 配置数据节点:datanode,数据源.表 t_order是逻辑表,属于t_order_1和t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds${1..2}.t_order_${1..2}

#抽取变量
common.shard4db=com.itheima.sharding.alg.Common4Tb

#-----------------------------------------------------------------------------------------------------------
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.sharding-column=user_id
#精确分片算法类名称,用于=和IN。该类需实现PreciseShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.precise-algorithm-class-name=${common.shard4db}
#范围分片算法类名称,用于BETWEEN,可选。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.range-algorithm-class-name=${common.shard4db}

#-----------------------------------------------------------------------------------------------------------

#抽取变量
common.shard4tb=com.itheima.sharding.alg.CommonAlgorithm4Tb

spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.sharding-column=order_id
#精确分片算法类名称,用于=和IN。该类需实现PreciseShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.precise-algorithm-class-name=${common.shard4tb}
#范围分片算法类名称,用于BETWEEN,可选。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.range-algorithm-class-name=${common.shard4tb}

#-----------------------------------------------------------------------------------------------------------

# 是否开启 SQL 显示,默认值: false
spring.shardingsphere.props.sql.show=true


    /**
     * @Description 测试精准匹配表的范围查询
     */
    @Test
    public void testRangeTable(){
        List<TOrder> tOrders = tOrderMapper.selectByRange(1l, 40l);
        System.out.println(tOrders);
    }
    /**
     * @Description
     */
    @Test
    public void testRangeTable2(){
        List<TOrder> tOrders = tOrderMapper.selectByRange2(2l,1l, 40l);
        System.out.println(tOrders);
    }

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值