首页 > 其他分享 >3、ShardingSphere实战(三)

3、ShardingSphere实战(三)

时间:2023-04-17 23:44:20浏览次数:49  
标签:实战 spring ShardingSphere 分片 shardingsphere sharding org import

一、前言:

本项目按照时间字段进行分表,需要提前将主表写入数据库
优势:
1、实现自动建表,且不需要配置 SQL
2、范围分表查询时自动排除不存在的表

 

二、项目实战:

1、创建主表:

CREATE TABLE `t_user` (
  `id` bigint(32) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `create_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

 

2、相关依赖:

注:ShardingSphere版本与Springboot版本要相互配置

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.iven</groupId>
    <artifactId>sharding-jdbc-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sharding-jdbc-demo</name>
    <description>sharding-jdbc-demo</description>

    <properties>
        <java.version>1.8</java.version>
        <mybatis-spring-boot>2.0.1</mybatis-spring-boot>
        <druid>1.1.16</druid>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis-spring-boot}</version>
        </dependency>
        <!--mybatis驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
        </dependency>
        <!--druid数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid}</version>
        </dependency>
        <!--lombok实体工具-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--JSON解析工具-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
        </dependency>
        <!-- huTool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.7</version>
        </dependency>
        <!--shardingsphere-->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
    </dependencies>

 

3、相关配置:

server.port=8080

#声明数据源
spring.shardingsphere.datasource.names=master
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
#MySQL5驱动:com.mysql.jdbc.Driver,MySQL6驱动:com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master.url=jdbc:mysql://localhost:3306/student?characterEncoding=utf-8
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=123456

#声明数据分表规则
#方式一:采用行表达式分片策略,根据id取模值分片,需要提前建好所有对应表
#指定所需分的表
#spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=master.t_user_$->{0..2}
#指定规则主键
#spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column=id
#指定分表规则
#spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression=t_user_$->{id % 3}

#方式二:采用标准分片策略,只支持对单个分片键为依据的分库分表(设定精准分片算法与范围分片算法),实现自动建表(需要手动建好主表),对时间进行分片
#指定所需分的表(如若需要可采用动态分配方式获取查询列表,否则当前只查询student.t_user)
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=master.t_user
#指定规则主键
spring.shardingsphere.sharding.tables.t_user.table-strategy.standard.sharding-column=create_at
#设定精准分片算法
spring.shardingsphere.sharding.tables.t_user.table-strategy.standard.precise-algorithm-class-name=com.iven.shardingjdbcdemo.config.DateShardingAlgorithm
#设定范围分片算法
spring.shardingsphere.sharding.tables.t_user.table-strategy.standard.range-algorithm-class-name=com.iven.shardingjdbcdemo.config.DateShardingAlgorithm

#打印SQL
spring.shardingsphere.props.sql.show=true


#指定mybatis配置路径
mybatis.mapperLocations=classpath:mapper/*.xml

#数据库名注入
db.schema-name=student

 

4、相关标准分片策略声明:

(1)、声明分表工具:

读取当前数据库缓存,用于自动建表

import com.iven.shardingjdbcdemo.dao.CommonMapper;
import com.iven.shardingjdbcdemo.model.CreateTableSql;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * 分表工具
 */
@Slf4j
public abstract class ShardingAlgorithmTool<T extends Comparable<?>> implements PreciseShardingAlgorithm<T>, RangeShardingAlgorithm<T> {

    @Autowired
    private static CommonMapper commonMapper;

    private static final HashSet<String> tableNameCache = new HashSet<>();

    /**
     * 手动注入
     */
    public static void setCommonMapper(CommonMapper commonMapper) {
        ShardingAlgorithmTool.commonMapper = commonMapper;
    }

    /**
     * 判断 分表获取的表名是否存在 不存在则自动建表
     *
     * @param logicTableName  逻辑表名(表头)
     * @param resultTableName 真实表名
     * @return 确认存在于数据库中的真实表名
     */
    public String shardingTablesCheckAndCreatAndReturn(String logicTableName, String resultTableName) {

        synchronized (logicTableName.intern()) {
            // 缓存中有此表 返回
            if (shardingTablesExistsCheck(resultTableName)) {
                return resultTableName;
            }
            // 缓存中无此表 建表 并添加缓存
            CreateTableSql createTableSql = commonMapper.selectTableCreateSql(logicTableName);
            String sql = createTableSql.getCreateTable();
            sql = sql.replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS");
            sql = sql.replace(logicTableName, resultTableName);
            commonMapper.executeSql(sql);
            tableNameCache.add(resultTableName);
        }

        return resultTableName;
    }

    /**
     * 判断表是否存在于缓存中
     *
     * @param resultTableName 表名
     * @return 是否存在于缓存中
     */
    public boolean shardingTablesExistsCheck(String resultTableName) {
        return tableNameCache.contains(resultTableName);
    }

    /**
     * 缓存重载方法
     *
     * @param schemaName 待加载表名所属数据库名
     */
    public static void tableNameCacheReload(JdbcTemplate jdbcTemplate, String schemaName) {
        // 读取指定数据库中所有表名(SELECT TABLES.TABLE_NAME FROM information_schema.TABLES WHERE TABLES.TABLE_SCHEMA=#{dbName} AND TABLE_TYPE = 'BASE TABLE')
        List<String> tableNameList = new ArrayList<>();
        DatabaseMetaData databaseMetaData = null;
        try {
            databaseMetaData = jdbcTemplate.getDataSource().getConnection().getMetaData();
            ResultSet tables = databaseMetaData.getTables(null, null, null, new String[]{"TABLE"});
            while (tables.next()) {
                tableNameList.add(tables.getString("TABLE_NAME"));
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        // 删除旧的缓存(如果存在)
        ShardingAlgorithmTool.tableNameCache.clear();
        // 写入新的缓存
        ShardingAlgorithmTool.tableNameCache.addAll(tableNameList);
    }

}

(2)、自动建表操作:

1)实体类:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 建表语句查询结果
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CreateTableSql {

    private String table;

    private String createTable;
}

2)、DAO类:

import com.iven.shardingjdbcdemo.model.CreateTableSql;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;


/**
 * 常用工具 mapper
 */
@Mapper
public interface CommonMapper {

    /**
     * 查询建表语句
     *
     * @param tableName 表名
     * @return 建表语句
     */
    CreateTableSql selectTableCreateSql(@Param("tableName") String tableName);

    /**
     * 执行SQL
     *
     * @param sql 待执行SQL
     */
    void executeSql(@Param("sql") String sql);

}

3)、mapper:

<?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.iven.shardingjdbcdemo.dao.CommonMapper">

    <resultMap id="selectTableCreateSqlResultMap" type="com.iven.shardingjdbcdemo.model.CreateTableSql">
        <result column="Table" property="table"/>
        <result column="Create Table" property="createTable"/>
    </resultMap>

    <select id="selectTableCreateSql" resultMap="selectTableCreateSqlResultMap">
        SHOW CREATE TABLE ${tableName}
    </select>

    <update id="executeSql">
        ${sql}
    </update>

</mapper>

(3)、标准分片策略声明:

指定分表规则,时间格式

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Range;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

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

/**
 * 日期分表策略
 */
@Slf4j
public class DateShardingAlgorithm extends ShardingAlgorithmTool<Date> {

    /**
     * 获取 指定分表
     * 精准分片算法
     * @param availableTargetNames 数据库中所有的事实表
     * @param preciseShardingValue 分片相关信息
     * @return 返回匹配的数据源
     */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> preciseShardingValue) {
        log.info("精准分片:数据库中所有的事实表:{},分片相关信息{}",availableTargetNames,preciseShardingValue);
        return shardingTablesCheckAndCreatAndReturn(preciseShardingValue.getLogicTableName(),
                preciseShardingValue.getLogicTableName() + DateUtil.format(preciseShardingValue.getValue(), "_yyyy_MM_dd"));
    }

    /**
     * 获取 范围分表
     * 范围分片算法
     */
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Date> rangeShardingValue) {
        log.info("范围分片:数据库中所有的事实表:{},分片相关信息{}",availableTargetNames,rangeShardingValue);
        Range<Date> valueRange = rangeShardingValue.getValueRange();
        Date lowerDate = valueRange.lowerEndpoint();
        Date upperDate = valueRange.upperEndpoint();
        List<String> tableNameList = new ArrayList<>();
        for (DateTime dateTime : DateUtil.rangeToList(DateUtil.beginOfDay(lowerDate), DateUtil.endOfDay(upperDate), DateField.DAY_OF_YEAR)) {
            String resultTableName = rangeShardingValue.getLogicTableName() + DateUtil.format(dateTime, "_yyyy_MM_dd");
            if (shardingTablesExistsCheck(resultTableName)) {
                tableNameList.add(resultTableName);
            }
        }
        return tableNameList;
    }
}

(4)、启动时将表载入缓存:

import com.iven.shardingjdbcdemo.dao.CommonMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 项目启动后 读取已有分表 进行缓存
 */
@Slf4j
@Order(value = 1) // 数字越小 越先执行
@Component
public class ShardingTablesLoadRunner implements CommandLineRunner {

    @Value("${db.schema-name}")
    private String schemaName;

    @Resource
    private CommonMapper commonMapper;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void run(String... args) throws Exception {
        // 给分表工具类注入属性
        ShardingAlgorithmTool.setCommonMapper(commonMapper);
        // 调用缓存重载方法
        ShardingAlgorithmTool.tableNameCacheReload(jdbcTemplate, schemaName);

        log.info("ShardingTablesLoadRunner start OK");
    }
}

 

5、测试:

插入的数据根据createAt时间字段进行自动建表与分表

(1)、相关实体类:

@Data
public class DemoVO implements Serializable {

    private Integer id;

    private String name;

    private Date createAt;

}

(2)、相关SQL:

    <resultMap id="BaseResultMap" type="com.iven.shardingjdbcdemo.model.DemoVO">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="creat_at" property="createAt" jdbcType="TIMESTAMP"/>
    </resultMap>

    <insert id="demoData" parameterType="com.iven.shardingjdbcdemo.model.DemoVO">
    INSERT INTO student.`t_user` (`id`, `name`, `create_at`)
    VALUES (#{id}, #{name}, #{createAt})
  </insert>

 

三、报错解决:

相关报错方案一;

相关报错方案二;

 

四、相关参考:

学习一;

学习二;

 

标签:实战,spring,ShardingSphere,分片,shardingsphere,sharding,org,import
From: https://www.cnblogs.com/Iven-L/p/17327928.html

相关文章

  • ssh基于key验证的实战
    实现目标实现同网段4-254的所有主机打通基于key验证的ssh登录点击查看代码PASS=123#设置网段最后的地址,4-255之间,越小扫描越快END=254IP=`ipaseth0|awk-F'[/]+''NR==3{print$3}'`NET=${IP%.*}../etc/os-releaserm-f/root/.ssh/id_rsa[-e./SCANIP.log......
  • 2、ShardingSphere中间件(二)
    一、ShardingSphere中间件:1、简介:(1)、概述:ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar这三款相互独立的产品组成。他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异......
  • vue3微信公众号商城项目实战系列(6)用户登录
    1.一个商城要实现购物的功能,需要能识别用户的身份,这样才能完成加购物车,下单,付款等操作。但微信公众号商城和PC端商城有些不一样,区别在于微信公众号商城使用微信支付的时候需要一个openid的参数(以后再具体讲)这个参数必须访问微信公众号提供的接口才能获取到,基于这个原因,用户登录......
  • 盘口语言-解密与实战
    股价高低点挂单特征解析量峰与股价的涨跌关系堆量与股价的涨跌关系实盘操作的进出场模型看懂主力机构坑爹的操盘手法,不再做无知的散户。从盘口语言的细节上把握盈利的关键点。第一章 技术分析的弊端和技术骗线一、向上做假突破的技术骗线1.方大集团(000055)2005年3月3......
  • SAP OData 开发实战教程:从入门到提高
    @目录SEGW-GatewayServiceBuilder使用RestfulABAPProgramming编程模型(简称RAP)开发OData服务使用SAPCloudApplicationProgramming编程模型开发OData服务详细目录本教程根据笔者在SAP研究院工作多年的实战经验,计划通过300篇以上的文章篇幅,深入介绍SAP三......
  • 盘点Python内置函数sorted()高级用法实战
    今日鸡汤清川带长薄,车马去闲闲。大家好,我是Python进阶者。一、前言前几天在Python钻石交流群有个叫【emerson】的粉丝问了一个Python排序的问题,这里拿出来给大家分享下,一起学习下。其实这里【瑜亮老师】、【布达佩斯的永恒】等人讲了很多,只不过对于基础不太好的小伙伴们来说,还是有......
  • Kubernetes(k8s)健康检查详解与实战演示(就绪性探针 和 存活性探针)
    一、概述Kubernetes中的健康检查主要使用就绪性探针(readinessProbes)和存活性探针(livenessProbes)来实现,service即为负载均衡,k8s保证service后面的pod都可用,是k8s中自愈能力的主要手段,主要基于这两种探测机制,可以实现如下需求:异常实例自动剔除,并重启新实例多种类型探针检......
  • 网络安全工程师教你Kali Linux:Windows计算机攻防实战技巧
    1.背景介绍msfvenom是msfpayload和msfencode的结合体,可利用msfvenom生成木马程序,并在目标机上执行,在本地监听上线,在黑客圈子,这款工具略有名气。之前的教程内容都是关于如何生成木马并进行攻击,而本节课我们着重讲解当用户计算机受到木马攻击的危害及演示防御木马病毒实战。2.准......
  • (之前的项目复习)我的Java项目实战--校园餐饮商户外卖系统07(优化)
    开发笔记七缓存优化问题说明用户数量多,系统访问量大频繁访问数据库,系统性能下降,用户体验差环境搭建maven坐标在项目的pom.xm1文件中导入springdataredis的maven坐标:点击查看代码<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-s......
  • Apache httpd 入门实战(2)--简单使用
    本文主要介绍Apache的实际使用,文中所使用到的软件版本:Centos7.9.2009、Httpd2.4.55。1、反向代理涉及到Https站点时,安装Apache时需要启用ssl,可参考 Apachehttpd入门实战(1)--概念及安装。1.1、被代理站点为Http站点打开conf/httpd.conf文件,修改或新增相应的配......