spring boot 八、 sharding-jdbc 分库分表 按月分表
在项目resources目录下新建com.jianmu.config.sharding.DateShardingAlgorithm 文件



新增yaml配置 数据源
spring:shardingsphere:props:sql:#是否在日志中打印 SQLshow: true#打印简单风格的 SQLsimple: truedatasource:names: pingxuanlogpingxuanlog:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db_jianmu_pingxuan_log?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8username: rootpassword: root#最大连接池数量max-active: 10#最小连接池数量min-idle: 5#初始化时建立物理连接的个数initial-size: 5#获取连接时最大等待时间,单位毫秒max-wait: 3000#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒time-between-eviction-runs-millis: 60000#配置一个连接在池中最小生存的时间,单位是毫秒min-evictable-idle-time-millis: 100000#用来检测连接是否有效的sql,要求是一个查询语句validation-query: SELECT 1 FROM DUAL#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。test-while-idle: true
新增yaml配置 sharding 分表规则
spring:shardingsphere:sharding:tables:t_act_vt_log:#配置数据节点,这里是按月分表,时间范围设置在202201 ~ 210012actual-data-nodes: pingxuanlog.t_act_vt_log_$->{202201..203012}table-strategy:standard:#使用标准分片策略,配置分片字段sharding-column: add_time# 精确匹配规则(自定义类)precise-algorithm-class-name: com.jianmu.config.sharding.DateShardingAlgorithm# 范围匹配规则(自定义类)range-algorithm-class-name: com.jianmu.config.sharding.DateShardingAlgorithmt_act_access_log:#配置数据节点,这里是按月分表,时间范围设置在202201 ~ 210012actual-data-nodes: pingxuanlog.t_act_access_log_$->{202201..203012}table-strategy:standard:#使用标准分片策略,配置分片字段sharding-column: add_time# 精确匹配规则(自定义类)precise-algorithm-class-name: com.jianmu.config.sharding.DateShardingAlgorithm# 范围匹配规则(自定义类)range-algorithm-class-name: com.jianmu.config.sharding.DateShardingAlgorithm
DataSourceConfiguration
package com.jianmu.config.sharding;import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;import javax.sql.DataSource;
import java.util.Map;/*** 动态数据源配置:* <p>* 使用{@link com.baomidou.dynamic.datasource.annotation.DS}注解,切换数据源** <code>@DS(DataSourceConfiguration.SHARDING_DATA_SOURCE_NAME)</code>**/
@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class DataSourceConfiguration {/*** 分表数据源名称*/public static final String SHARDING_DATA_SOURCE_NAME = "sharding";/*** 动态数据源配置项*/private final DynamicDataSourceProperties dynamicDataSourceProperties;private final ShardingDataSource shardingDataSource;@Autowiredpublic DataSourceConfiguration(DynamicDataSourceProperties dynamicDataSourceProperties, @Lazy ShardingDataSource shardingDataSource) {this.dynamicDataSourceProperties = dynamicDataSourceProperties;this.shardingDataSource = shardingDataSource;}/*** 将shardingDataSource放到了多数据源(dataSourceMap)中**/@Beanpublic DynamicDataSourceProvider dynamicDataSourceProvider() {Map<String, DataSourceProperty> datasourceMap = dynamicDataSourceProperties.getDatasource();return new AbstractDataSourceProvider() {@Overridepublic Map<String, DataSource> loadDataSources() {Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);// 将 sharding jdbc 管理的数据源也交给动态数据源管理dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingDataSource);return dataSourceMap;}};}/*** 将动态数据源设置为首选的* 当spring存在多个数据源时, 自动注入的是首选的对象* 设置为主要的数据源之后,就可以支持sharding jdbc原生的配置方式*/@Primary@Beanpublic DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());dataSource.setStrict(dynamicDataSourceProperties.getStrict());dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());dataSource.setProvider(dynamicDataSourceProvider);dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());dataSource.setSeata(dynamicDataSourceProperties.getSeata());return dataSource;}
}
package com.jianmu.config.sharding;import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthContributorAutoConfiguration;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator;
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;import javax.sql.DataSource;
import java.util.Map;/*** @author kong*/
@Configuration
public class DataSourceHealthConfig extends DataSourceHealthContributorAutoConfiguration {@Value("${spring.datasource.dbcp2.validation-query:select 1}")private String defaultQuery;public DataSourceHealthConfig(Map<String, DataSource> dataSources, ObjectProvider<DataSourcePoolMetadataProvider> metadataProviders) {super(dataSources, metadataProviders);}@Overrideprotected AbstractHealthIndicator createIndicator(DataSource source) {DataSourceHealthIndicator indicator = (DataSourceHealthIndicator) super.createIndicator(source);if (!StringUtils.hasText(indicator.getQuery())) {indicator.setQuery(defaultQuery);}return indicator;}
}
package com.jianmu.config.sharding;import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.jianmu.tools.ApplicationContextTools;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
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.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;/**sharding 分库分表策略配置:按照年月 如t_act_vt_log_202208**/
@Slf4j
public class DateShardingAlgorithm implements PreciseShardingAlgorithm<LocalDateTime>, RangeShardingAlgorithm<LocalDateTime> {private final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMM");@Overridepublic String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<LocalDateTime> psv) {final String table = psv.getLogicTableName();final String prefix = table + "_";if (log.isDebugEnabled()) {log.debug("分表更新");}TableService tableService = (TableService) ApplicationContextTools.getBean(TableService.class);//添加日期final String logicTable = prefix + psv.getValue().format(this.format);boolean exist = tableService.exist(logicTable);if (log.isDebugEnabled()) {log.debug("更新: {} 存在:{}", logicTable, exist);}//匹配到了if (exist) {return logicTable;}//未匹配到if (log.isDebugEnabled()) {log.debug("sharding 未匹配到表,需要创建");}//创建这张表tableService.copy(logicTable, table);return logicTable;}/*** 范围匹配*/@SneakyThrows@Overridepublic Collection<String> doSharding(Collection<String> collection, RangeShardingValue<LocalDateTime> rsv) {final String table = rsv.getLogicTableName();final String prefix = table + "_";if (log.isDebugEnabled()) {log.debug("分表查询 表:{}", table);}TableService tableService = (TableService) ApplicationContextTools.getBean(TableService.class);List<String> tables = tableService.tables();Range<LocalDateTime> range = rsv.getValueRange();//计算出时间范围内的所有日期final int upper = range.hasUpperBound() ? Integer.parseInt(range.upperEndpoint().toLocalDate().format(this.format)) : 0;final int lower = range.hasLowerBound() ? Integer.parseInt(range.lowerEndpoint().toLocalDate().format(this.format)) : 0;List<String> validTables = this.validTables(prefix, tables, upper, lower);if (log.isDebugEnabled()) {log.debug("查询表:{}", JSON.toJSONString(validTables));}if (CollectionUtils.isEmpty(validTables)) {if (log.isDebugEnabled()) {log.debug("查询表不存在 改查原始表");}return Lists.newArrayList(table);}return validTables;}private List<String> validTables(String prefix, List<String> tables, int upper, int lower) {if (log.isDebugEnabled()) {log.debug("上界:{},下界:{}", upper, lower);}return tables.parallelStream().filter(i -> {if (i.contains(prefix)) {final String date = i.replace(prefix, "");if (date.matches("[0-9]*")) {final int mouth = Integer.parseInt(date);if (upper > 0 && lower > 0) {return mouth <= upper && mouth >= lower;} else {if (upper > 0) {return mouth <= upper;}if (lower > 0) {return mouth >= lower;}}}}return false;}).collect(Collectors.toList());}}
package com.jianmu.config.sharding;public class ShardingConstant {public static final String ORIGINAL_DATABASE = "db_jianmu_pingxuan_log";
}
package com.jianmu.config.sharding;import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.ExecutionException;public interface TableService {/*** 返回所有表*/List<String> tables() throws ExecutionException, SQLException;boolean exist(String table);/*** 精确删除表*/boolean drop(String table);/*** 旧表复制为新表*/boolean copy(String newTable, String usedTable);
}
package com.jianmu.config.sharding;import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.jianmu.constant.SysRedisConstant;
import com.jianmu.mapper.system.TableMapper;
import com.jianmu.tools.JdbcTools;
import com.jianmu.tools.log.LogTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;import java.sql.SQLException;
import java.util.List;@Slf4j
@Service
@DS("sharding")
public class TableServiceImpl implements TableService {private final TableMapper tableMapper;private final RedisTemplate<String, Object> redis;private final ValueOperations<String, Object> redisValue;private final DynamicRoutingDataSource dynamicRoutingDataSource;@Autowiredpublic TableServiceImpl(TableMapper tableMapper, RedisTemplate<String, Object> redis, DynamicRoutingDataSource dynamicRoutingDataSource) {this.tableMapper = tableMapper;this.redis = redis;this.redisValue = redis.opsForValue();this.dynamicRoutingDataSource = dynamicRoutingDataSource;}@Overridepublic List<String> tables() throws SQLException {List<String> tables = (List<String>) this.redisValue.get(SysRedisConstant.TABLES);if (tables == null) {List<String> list = JdbcTools.tables(this.dynamicRoutingDataSource.getDataSource(DataSourceConfiguration.SHARDING_DATA_SOURCE_NAME).getConnection(), ShardingConstant.ORIGINAL_DATABASE);//每24小时更新一次this.redisValue.set(SysRedisConstant.TABLES, list, 86400);return list;}return tables;}@Overridepublic boolean exist(String table) {try {Integer exist = this.tableMapper.exist(table);if (log.isDebugEnabled()) {log.debug("表:{} 存在:{}", table, exist);}return true;} catch (Exception e) {LogTools.err(e);return false;}}@Overridepublic boolean drop(String table) {boolean flag = this.tableMapper.drop(table) >= 0;if (flag) {this.delCache();}return flag;}@Overridepublic boolean copy(String newTable, String usedTable) {boolean flag = this.tableMapper.copy(newTable, usedTable) >= 0;if (flag) {this.delCache();}return flag;}private void delCache() {this.redis.delete(SysRedisConstant.TABLES);}}
t_act_vt_log 为每次自动生成的基础表 需要在这个表建好索引等

相关文章:
spring boot 八、 sharding-jdbc 分库分表 按月分表
在项目resources目录下新建com.jianmu.config.sharding.DateShardingAlgorithm 文件 新增yaml配置 数据源 spring:shardingsphere:props:sql:#是否在日志中打印 SQLshow: true#打印简单风格的 SQLsimple: truedatasource:names: pingxuanlogpingxuanlog:type: com.alibaba.dru…...
Java 8 中Stream流的一些用法
public class Djmxlist {private String dxmc;private Integer sl;public String getDxmc() {return dxmc;}public void setDxmc(String dxmc) {this.dxmc dxmc;}public Integer getSl() {return sl;}public void setSl(Integer sl) {this.sl sl;} }插入一下数据 List<Djm…...
Elasticsearch 8.10 中引入查询规则 - query rules
作者:Kathleen DeRusso 我们很高兴宣布 Elasticsearch 8.10 中的查询规则! 查询规则(query rules)允许你根据正在搜索的查询词或根据作为搜索查询的一部分提供的上下文信息来更改查询。 什么是查询规则? 查询规则&…...
Windows PostgreSql 创建多个数据库目录
1 使用默认用户Administrator 1.1初始化数据库目录 E:\Program Files\PostgreSQL\13> .\bin\initdb -D G:\DATA\pgsql\data3 -W -A md5 1.2连接数据库 这时User为Administrator,密码就是你刚才设置的,我设置的为123456,方便测试。 2 添加…...
Java AOP Framework概述
Java AOP Framework概述 1. AspectJ1.1 使用AspectJ进行切面编程 2. Spring AOP2.1 使用Spring AOP进行切面编程2.2 如何决定使用哪种动态代理2.3 如何通过配置指定代理方式2.4 Spring AOP和AspectJ的关系 3. Spring Boot AOP4. 扩展4.1 AspectJ织入方式详解 参考 Java常用的AO…...
220V转12V芯片-交流45v-265v输入,固定12v输出峰值电流600MA
标题:220V转12V芯片,实现宽电压输入和固定12V输出 摘要:本文介绍了一款具备宽电压输入范围(45V-265V)和固定12V输出的220V转12V芯片。该芯片内置了650V高压MOS管,并通过CS电阻调节输出电流,最大…...
TOGAF架构开发方法—初步阶段
本章描述了满足新企业体系结构业务指令所需的准备和启动活动,包括组织特定体系结构框架的定义和原则的定义。 一、目标 初步阶段的目标是: 确定组织所需的体系结构功能: 审查进行企业架构的组织背景确定受体系结构功能影响的企业组织的元素并确定其范围确定与架构功能相交的…...
软件定制APP开发步骤分析|小程序
软件定制APP开发步骤分析|小程序 软件定制开发步骤: 1.需求分析: 这是软件定制开发的第一步,也是最关键的一步。在这个阶段,软件开发团队需要与客户进行沟通,了解客户的具体需求和期望。通过讨论和交流,确…...
postman接口传参案例
目录 案例1: 接口A 接口B 案例2: //断言 案例1: 接口A 根据返回值需要从返回值中提取userid值,在Tests标签栏下编写脚本 //获取返回的响应值,并转化为json格式 var jsonData pm.response.json(); // 获取返回…...
【2023华为杯A题】WLAN网络信道接入机制建模(代码、思路.....)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
CFCA企业版通配符SSL证书
CFCA是中国CFCA企业版通配符SSL证书金融认证中心的缩写,即China Financial Certification Authority。它是一家经过中国人民银行和国家信息安全机构批准成立的国家级权威安全认证机构,也是国际CA浏览器联盟组织(CA/Browser Forum)…...
基于ASCON的AEAD
1. 引言 前序博客: ASCON:以“慢而稳”赢得NIST轻量级加密算法标准密码学中的AEAD(authenticated encryption with associated data) 对称密钥加密过去数年来已发生改变,具体为: 当今主要使用stream ciphers,因其比…...
汇编宏伪指令介绍
1、汇编宏伪指令介绍 .macro macname macargs .endm(1)“.macro"和”.endm"表示宏定义的开始和结束; (2) “.macro"后面接着宏定义的名字,然后是参数,参数后面的宏定义的实现…...
优化系统报错提示信息,提高人机交互(一)
1、常规报错及处理 package com.example.demo.controller;import com.example.demo.service.IDemoService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.w…...
FPGA纯verilog实现8路视频拼接显示,提供工程源码和技术支持
目录 1、前言版本更新说明免责声明 2、我已有的FPGA视频拼接叠加融合方案3、设计思路框架视频源选择OV5640摄像头配置及采集静态彩条视频拼接算法图像缓存视频输出 4、vivado工程详解5、工程移植说明vivado版本不一致处理FPGA型号不一致处理其他注意事项 6、上板调试验证并演示…...
spring boot项目一次性能测试的总结
满足标准:并发大于等于100 ,平均响应时间小于等于3秒 项目在压测过程中并发数只有50,在并发数100的情况下有很多请求链接是失败的 我们该如何入手去处理这些问题并提高并发数呢? 1、首先从压测结果入手,对不满足标准…...
10分钟设置免费海外远程桌面
前言 本教程将向您介绍如何使用 Amazon Lightsail 服务的免费套餐轻松搭建属于您的远程桌面。依托于 Amazon 全球可用区,您可以在世界各地搭建符合您配置需求的远程桌面。 本教程需要先拥有亚马逊云科技海外账户。现在注册亚马逊云科技账户可以享受12个月免费套餐…...
基于复旦微的FMQL45T900全国产化ARM核心模块(100%国产化)
TES745D是一款基于上海复旦微电子FMQL45T900的全国产化ARM核心板。该核心板将复旦微的FMQL45T900(与XILINX的XC7Z045-2FFG900I兼容)的最小系统集成在了一个87*117mm的核心板上,可以作为一个核心模块,进行功能性扩展,能…...
2023.9.11 关于传输层协议 UDP和TCP 详解
目录 UDP协议 TCP协议 TCP十大核心机制 确认应答 超时重传 连接管理(三次握手 四次挥手) 滑动窗口 流量控制 拥塞控制 延时应答 捎带应答 面向字节流 粘包问题 TCP 中的异常处理 经典面试题 对比 TCP 和 UDP 如何使用 UDP 实现可靠传…...
thinkphp8路由
thinkphp8已出来有好一段时间了。这些天闲来无事,研究了下tp8的路由。默认情况下,tp8的路由是在route\app.php的文件里。但在实际工作中,我们并不会这样子去写路由。因为这样不好管理。更多的,是通过应用级别去管理路由。假如项目…...
intv_ai_mk11惊艳案例:用‘分点说明’指令生成直播复盘报告,覆盖数据/话术/节奏
intv_ai_mk11惊艳案例:用分点说明指令生成直播复盘报告,覆盖数据/话术/节奏 1. 直播复盘报告生成效果展示 直播结束后,运营团队最头疼的就是整理复盘报告。传统方式需要人工回看录像、统计数据、分析话术,耗时耗力。而使用intv_…...
免费跨平台游戏打包神器:轻松将HTML游戏转换为专业桌面应用
免费跨平台游戏打包神器:轻松将HTML游戏转换为专业桌面应用 【免费下载链接】twine-app-builder Automatically generate Windows and macOS versions of your Twine games, for free! 项目地址: https://gitcode.com/gh_mirrors/tw/twine-app-builder 还在为…...
终极PoeCharm指南:如何用中文版Path of Building轻松打造流放之路最强角色
终极PoeCharm指南:如何用中文版Path of Building轻松打造流放之路最强角色 【免费下载链接】PoeCharm Path of Building Chinese version 项目地址: https://gitcode.com/gh_mirrors/po/PoeCharm 还在为《流放之路》复杂的装备搭配和天赋选择头疼吗ÿ…...
Dify + LangChain + FastAPI 三端协同集成方案:企业私有化部署必读的6层安全加固清单
第一章:Dify低代码平台集成概述 Dify 是一个开源的 LLM 应用开发平台,支持通过可视化编排与少量代码快速构建 AI 原生应用。其核心价值在于将模型调用、提示工程、RAG 检索、工作流编排等能力封装为可复用组件,使开发者无需从零搭建后端服务即…...
终极指南:5个快速解决Ryujinx模拟器常见问题的完整教程
终极指南:5个快速解决Ryujinx模拟器常见问题的完整教程 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx Ryujinx是一款用C#编写的开源Nintendo Switch模拟器,致力…...
【原创代码】基于贝叶斯优化的PatchTST综合能源负荷多变量时间序列预测
✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书…...
Python自动化处理配置文件:项目配置管理的最佳实践
项目做大了,配置文件一多就头疼:开发环境用一套配置,生产环境用另一套;有些参数需要加密保存;配置文件分布在不同地方难管理。今天分享Python自动化处理配置文件的完整方案,包括配置读取、环境切换、加密存储、配置校验等功能。 环境准备 pip install python-dotenv py…...
5分钟学会Llama Factory:可视化操作,轻松实现大模型训练与微调
5分钟学会Llama Factory:可视化操作,轻松实现大模型训练与微调 1. 为什么选择Llama Factory? 在人工智能领域,大语言模型(LLM)的训练和微调一直是技术门槛较高的工作。传统方法需要编写大量代码、处理复杂的环境配置,…...
Arduino多任务进阶:手把手教你用TaskScheduler实现智能小车避障与巡线‘双模切换’
Arduino多任务实战:智能小车双模切换系统设计与实现 当你的Arduino智能小车需要同时处理避障和巡线功能时,单线程的loop()结构很快就会遇到性能瓶颈。超声波传感器的实时测距与红外传感器的线路检测相互竞争处理器时间,导致响应延迟或功能失效…...
惊艳展示!CYBER-VISION零号协议实时分割效果:盲道、行人、车辆精准识别
惊艳展示!CYBER-VISION零号协议实时分割效果:盲道、行人、车辆精准识别 1. 视觉革命:当AI遇见助盲科技 在熙攘的城市街道上,视障人士的每一次出行都是一场充满未知的挑战。传统的盲杖只能探测到脚边的障碍,而CYBER-V…...
