SSM项目引入sharding JDBC进行分表

  • 注意点:

    1. 本次集成sharing-jdbc 4.1.1,由于各个版本差别比较大,配置方式差别也特别大,请根据官方文档进行配置!
      官方配置路径:https://shardingsphere.apache.org/document/legacy/4.x/document/cn/manual/sharding-jdbc/configuration/config-spring-namespace/
    2. 本次展示的是不分库,按年进行分表,如有使用要根据自己的业务进行修改!
    3. 查询时候要把逻辑列带上,这样能精确定位到唯一的一张表!如果逻辑列为空会这几个表全部查一遍,然后各个表符合的数据的全部展示出来!
    4. 由于没有查到cat集成sharing-jdbc相关配置,dataSource专门供cat使用,导致显示sql时候还是原来的样子,但是不影响功能!

1. 引入Maven依赖

<!-- 分库分表 -->
<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version>
</dependency>
<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-namespace</artifactId><version>4.1.1</version>
</dependency>

2. 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"xmlns:sharding="http://shardingsphere.apache.org/schema/shardingsphere/sharding"xmlns:bean="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache  http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://shardingsphere.apache.org/schema/shardingsphere/shardinghttp://shardingsphere.apache.org/schema/shardingsphere/sharding/sharding.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"default-lazy-init="true"><bean id="ds1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClass}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.user}" /><property name="password" value="${jdbc.password}" /><property name="maxActive" value="${jdbc.maxActive}" /><property name="initialSize" value="${jdbc.initialSize}" /><property name="maxWait" value="6000" /><property name="minIdle" value="${jdbc.initialSize}" /><property name="timeBetweenEvictionRunsMillis" value="60000" /><property name="minEvictableIdleTimeMillis" value="300000" /><property name="removeAbandoned" value="true" /> <!-- 打开removeAbandoned功能 --><property name="removeAbandonedTimeout" value="1800" /> <!-- 1800秒,也就是30分钟 --><property name="logAbandoned" value="true" /> <!-- 关闭abanded连接时输出错误日志 --><property name="validationQuery" value="SELECT 'x'" /><property name="testWhileIdle" value="true" /><property name="testOnBorrow" value="false" /><property name="testOnReturn" value="false" /><property name="connectionProperties" value="druid.stat.mergeSql=true" /><property name="filters" value="stat,slf4j" /></bean><!--由于cat无法集成shardingjdbc 所以此处单独cat使用--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClass}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.user}" /><property name="password" value="${jdbc.password}" /><property name="maxActive" value="${jdbc.maxActive}" /><property name="initialSize" value="${jdbc.initialSize}" /><property name="maxWait" value="6000" /><property name="minIdle" value="${jdbc.initialSize}" /><property name="timeBetweenEvictionRunsMillis" value="60000" /><property name="minEvictableIdleTimeMillis" value="300000" /><property name="removeAbandoned" value="true" /> <!-- 打开removeAbandoned功能 --><property name="removeAbandonedTimeout" value="1800" /> <!-- 1800秒,也就是30分钟 --><property name="logAbandoned" value="true" /> <!-- 关闭abanded连接时输出错误日志 --><property name="validationQuery" value="SELECT 'x'" /><property name="testWhileIdle" value="true" /><property name="testOnBorrow" value="false" /><property name="testOnReturn" value="false" /><property name="connectionProperties" value="druid.stat.mergeSql=true" /><property name="filters" value="stat,slf4j" /></bean><bean:properties id="workerId"><prop key="worker.id">${workerId}</prop></bean:properties><bean id="msPushShardingAlgorithm" class="com.xxx.xxx.biz.study.manage.config.MsPushShardingAlgorithm" /><sharding:standard-strategy id="pushTableStrategy" sharding-column="create_date" precise-algorithm-ref="msPushShardingAlgorithm" range-algorithm-ref="msPushShardingAlgorithm"/><sharding:key-generator id="idKeyGenerator" type="SNOWFLAKE" column="id" props-ref="workerId"/><sharding:data-source id="shardingDataSource"><sharding:sharding-rule data-source-names="ds1"><sharding:table-rules><sharding:table-rule logic-table="biz_ms_push"actual-data-nodes="ds1.biz_ms_push_20$->{21..25}"table-strategy-ref="pushTableStrategy" key-generator-ref="idKeyGenerator"  /><sharding:table-rule logic-table="biz_ms_push_record"actual-data-nodes="ds1.biz_ms_push_record_20$->{21..25}"table-strategy-ref="pushTableStrategy" key-generator-ref="idKeyGenerator"  /><sharding:table-rule logic-table="biz_ms_push_record_link"actual-data-nodes="ds1.biz_ms_push_record_link_20$->{21..25}"table-strategy-ref="pushTableStrategy" key-generator-ref="idKeyGenerator"  /></sharding:table-rules><sharding:binding-table-rules><sharding:binding-table-rule logic-tables="biz_ms_push,biz_ms_push_record,biz_ms_push_record_link" /></sharding:binding-table-rules></sharding:sharding-rule><sharding:props><prop key="sql.show">true</prop></sharding:props></sharding:data-source><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="shardingDataSource" /><property name="mapperLocations"><array><value>classpath:mapper/*.xml</value><value>classpath:mapper/ext/*.xml</value></array></property><!-- 根据实际工程路径 修改 typeAliasesPackage --><property name="typeAliasesPackage" value="com.xxx.xxx.biz.study.manage.po" /><property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property><property name="plugins"><array><bean class="com.github.pagehelper.PageHelper"><!-- 这里的几个配置主要演示如何使用,如果不理解,一定要去掉下面的配置 --><property name="properties"><value>dialect=mysqlreasonable=falsesupportMethodsArguments=truereturnPageInfo=checkparams=count=countSql</value></property></bean><!-- 增加sql监控 --><bean class="com.xxx.xxx.mybatis.interceptors.CatMybatisInterceptor"><!-- dataSource属性作用:获取数据库链接字符串 --><property name="dataSource" ref="dataSource" /></bean></array></property></bean><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="addToConfig" value="true" /><property name="basePackage" value="com.xxx.xxx.biz.study.manage.mapper" /></bean><bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype"><constructor-arg index="0" ref="sqlSessionFactory" /></bean>
</beans>

1.各个配置说明

1.数据源

  • 目前只是分表,如果想分库,可以配置多数据源,注意:数据源id要不同,规则要配置好)

2.加载各种配置

解释:

1. 加载分表的规制,配置如何去根据直接业务需求进行分表(配置里面是保存的逻辑以及查询的逻辑)
<bean id="msPushShardingAlgorithm" class="com.xxx.xxx.biz.study.manage.config.MsPushShardingAlgorithm" />
2. 此代码是配置具体的列,以及规制!详情见下图
<sharding:standard-strategy id="pushTableStrategy" sharding-column="create_date" precise-algorithm-ref="msPushShardingAlgorithm" range-algorithm-ref="msPushShardingAlgorithm"/>

3. 这是主键的生成规则(官方默认两种SNOWFLAKE/UUID),因为已经分表原先的主键自增已经不适合现在业务,所以本次选择雪花算法!详情见下图:
<sharding:key-generator id="idKeyGenerator" type="SNOWFLAKE" column="id" props-ref="workerId"/>

注意:1.如果你是多主机部署请为了避免生成重复请注意机器id(workerId)

​ 2. 多主机部署如果服务器本地时间不一致请配置最大容忍时钟回退时间

​ 3.1 主键的生成规则

​ 3.2 雪花算法多主机配置项

3. 集成

解释:

​ <sharding:data-source />

名称 类型 说明
id 属性 Spring Bean Id
sharding-rule 标签 数据分片配置规则
props (?) 标签 属性配置

<sharding:sharding-rule />

名称 类型 说明
data-source-names 属性 数据源Bean列表,多个Bean以逗号分隔
table-rules 标签 表分片规则配置对象
logic-table 标签 逻辑表名称
actual-data-nodes (?) 标签 由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持inline表达式。缺省表示使用已知数据源与逻辑表名称生成数据节点,用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)或只分库不分表且所有库的表结构完全一致的情况
table-strategy-ref (?) 属性 表分片策略,对应<sharding:standard-strategy >中的策略Id,缺省表示使用<sharding:sharding-rule />配置的默认表分片策略
key-generator-ref (?) 属性 自增列值生成器引用,缺省表示使用默认自增列值生成器
binding-table-rule (+) 属性 绑定表规则
sql.show (?) 属性 是否开启SQL显示,默认值: false

3. 配置类

  1. 保存或者查找的分片规则

    @Log4j
    public class MsPushShardingAlgorithm implements PreciseShardingAlgorithm, RangeShardingAlgorithm<Integer> {/*** 缓存存在的表*/private List<String> msPushTables=new ArrayList<>();private List<String> msPushTablesList=new ArrayList<>() ;private Boolean isLoad = false;//这是保存的分片规则@Overridepublic String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {String logicTableName = shardingValue.getLogicTableName() + "_";for (String tableName : msPushTablesList) {if (tableName.equals(logicTableName)){isLoad = true;break;}else {isLoad = false;}}if (!isLoad) {PageHelper.orderBy(null);msPushTables.addAll(DBUtil.getAllSystemLogTable(logicTableName));msPushTablesList.add(logicTableName);isLoad = true;}String target = shardingValue.getValue().toString();String year = target.substring(target.lastIndexOf("_") + 1, target.lastIndexOf("_") + 5);if (!msPushTables.contains(logicTableName+year)) {//此处是创建表的逻辑,sql见下:DBUtil.createLogTable(logicTableName, year);msPushTables.add(year);}return shardingValue.getLogicTableName()+"_" +year;}@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Integer> shardingValue) {Collection<String> availables = new ArrayList<>();Range valueRange = shardingValue.getValueRange();for (String target : availableTargetNames) {Integer shardValue = Integer.parseInt(target.substring(target.lastIndexOf("_") + 1, target.lastIndexOf("_") + 5));if (valueRange.hasLowerBound()) {String lowerStr = valueRange.lowerEndpoint().toString();Integer start = Integer.parseInt(lowerStr.substring(0, 4));if (start - shardValue > 0) {continue;}}if (valueRange.hasUpperBound()) {String upperStr = valueRange.upperEndpoint().toString();Integer end = Integer.parseInt(upperStr.substring(0, 4));if (end - shardValue < 0) {continue;}}availables.add(target);}return availables;}}
    

    DBUtil:

    @Component
    public class DBUtil {@Autowiredprivate  MsPushRecordPoWithBLOBsMapper msPushRecordPoWithBLOBsMapper;private  static MsPushRecordPoWithBLOBsMapper pushRecordPoWithBLOBsMapper;//解决静态方法无法注入问题@PostConstructpublic void init() {pushRecordPoWithBLOBsMapper = msPushRecordPoWithBLOBsMapper;}public static List<String> getAllSystemLogTable(String logicTableName) {logicTableName=logicTableName+"2";List<String> allSystemLogTable = pushRecordPoWithBLOBsMapper.getAllSystemLogTable(logicTableName);return allSystemLogTable;}public static void createLogTable( String logicTableName,String year) {String tableName = logicTableName + year;if (logicTableName.equals("biz_ms_push_record_")){pushRecordPoWithBLOBsMapper.createRecordNewTable(tableName);}else if(logicTableName.equals("biz_ms_push_")){pushRecordPoWithBLOBsMapper.createPushNewTable(tableName);}else if(logicTableName.equals("biz_ms_push_record_link_")){pushRecordPoWithBLOBsMapper.createPushRecordLinkNewTable(tableName);}}
    }
    

    createPushNewTable:

CREATE TABLE ${tableName}
(`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`ms_push_id` bigint(20) DEFAULT NULL COMMENT '推送id',`total_count` int(10) DEFAULT NULL COMMENT '实发送量',`sent_count` int(10) DEFAULT NULL COMMENT '到达量',`open_count` int(10) DEFAULT NULL COMMENT '打开量',`dismiss_count` int(10) DEFAULT NULL COMMENT '忽略量',`task_id` varchar(100) DEFAULT NULL COMMENT '任务id',`status` int(1) DEFAULT NULL COMMENT '状态(1成功,2失败)',`application_unique` varchar(100) DEFAULT NULL COMMENT '设备类型标识',`remark` varchar(2000) DEFAULT NULL COMMENT '备注',`task_status_remark` varchar(2000) DEFAULT NULL COMMENT '任务状态备注',`create_date` datetime DEFAULT NULL COMMENT '创建时间',`update_date` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`) USING BTREE,KEY                  `ms_push_id` (`ms_push_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=864 DEFAULT CHARSET=utf8 COMMENT='消息推送记录';
  1. 由于是分布式项目,避免生产id重复,故配置工作id,如果不配置默认为0;
<bean:properties id="workerId"><prop key="worker.id">${workerId}</prop>
</bean:properties>

**注意:**可以根据hostname,ip生成不重复的3位以内数字,只要各个服务器生成的不一致就行,本案例采用ip相加(请及时验证)!

public static Long getInet4Address() {Enumeration<NetworkInterface> nis;InetAddress address =null;try {nis = NetworkInterface.getNetworkInterfaces();for (; nis.hasMoreElements(); ) {NetworkInterface ni = nis.nextElement();Enumeration<InetAddress> ias = ni.getInetAddresses();for (; ias.hasMoreElements(); ) {InetAddress   ia  = ias.nextElement();//ia instanceof Inet6Address && !ia.equals("")if (ia instanceof Inet4Address && !ia.getHostAddress().equals("127.0.0.1")) {address = ia;}}};// IP地址byte[]数组形式,这个byte数组的长度是4,数组0~3下标对应的值分别是172,16,206,54byte[] ipAddressByteArray = address.getAddress();// 由这里计算workerId源码可知,workId由两部分组成:int  workerId=0;for (byte byteNum : ipAddressByteArray) {workerId += byteNum & 0xFF;}logger.info("==============address是:"+address+"============================================测试workerId是:"+workerId);return Long.valueOf(workerId);} catch (SocketException e) {logger.error("============================================获取ip错误",e);}return  0L;
}

赋值 workerId

@Configuration
@Slf4j
public class WorkIdConfig {private static Logger logger = LoggerFactory.getLogger(WorkIdConfig.class);static {long workId = 0;try {workId = SnowflakeIdWorker.getInet4Address();} catch (Exception e) {logger.error("生成workId发生异常.", e);}logger.info("========最终workerID是:" + workId + "============");System.setProperty("workerId", String.valueOf(workId));}}

SSM项目引入sharding JDBC进行分表相关推荐

  1. Spring boot + Sharding JDBC 分库分表 及 分布式事务处理

    Sharding JDBC 基础概念 Apache ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈,它由 JDBC.Proxy 和 Sidecar(规划中)这 3 款既能够 ...

  2. 使用sharding做分库分表,使用jpa,发生的save不报错,数据库缺插不进去数据的问题

    先讲讲问题的诞生,我们项目起初没有引进 sharding分库,而是在项目上线前,才做的分库分表.也就是之前的业务都写好的,所以知道业务代码没有任何问题. 然后引入 sharding 的相关的依赖以后, ...

  3. efcore根据多个条件更新_EFCore.Sharding(EFCore开源分表框架)

    简介 本框架旨在为EF Core提供Sharding(即读写分离分库分表)支持,不仅提供了一套强大的普通数据操作接口,并且降低了分表难度,支持按时间自动分表扩容,提供的操作接口简洁统一. 源码地址:E ...

  4. EFCore.Sharding(EFCore开源分表框架)

    简介 本框架旨在为EF Core提供Sharding(即读写分离分库分表)支持,不仅提供了一套强大的普通数据操作接口,并且降低了分表难度,支持按时间自动分表扩容,提供的操作接口简洁统一. 源码地址:E ...

  5. ShardingSphere JDBC 分库分表 读写分离 数据加密

    简介 在上篇文章中,在本地搭建了运行环境,本地来体验下ShardingSphere JDBC的三个功能:分库分表.读写分离.数据加密 示例运行 首先把概念先捋一捋,参考下面的文档: 数据分片 读写分离 ...

  6. Spring boot项目集成Sharding Jdbc

    环境 jdk:1.8 framework: spring boot, sharding jdbc database: MySQL 搭建步骤 在pom 中加入sharding 依赖 <depend ...

  7. mysql sharding 方案_mysql sharding 方案 分库分表(sharding)系列(4)

    图1. Sharding实现层面与相关框架/产品 在DAO层实现 当团队决定自行实现sharding的时候,DAO层可能是嵌入sharding逻辑的首选位置,因为在这个层面上,每一个DAO的方法都明确 ...

  8. MySQL数据库性能优化--数据分库分表

    目录 前言 1.什么时候需要分库分表? 1.1.第一次改造 1.2.分库分表的必要性 1.3.第二次改造 2.分库分表应该怎么分? 3.垂直分库会带来哪些问题? 3.1.跨库的关联查询 3.2.分布式 ...

  9. 理解Sharding jdbc原理,看这一篇就够了

    相比于Spring基于AbstractRoutingDataSource实现的分库分表功能,Sharding jdbc在单库单表扩展到多库多表时,兼容性方面表现的更好一点.例如,spring实现的分库 ...

最新文章

  1. Spring Boot 最最最常用的注解梳理
  2. DJANGO获取用户访问IP
  3. 【计算机网络】物理层 : 数据通信 ( 数据通信模型 | 信源 | 信宿 | 信道 | 通信方式 | 单工 | 半双工 | 全双工 | 数据传输方式 | 串行 | 并行 )
  4. 服务器的攻与防(firewall 禁止指定Ip)
  5. 长沙校园招聘总结-做为技术面试官
  6. Linux kernel 3.10内核源码分析--slab原理及相关代码
  7. 前端学习(3033):vue+element今日头条管理-反馈
  8. pytorch入门使用
  9. 关于服务限流的一些思考
  10. 〖Demo〗-- 多级评论
  11. Chrome 强制显示最小字体为 12px的解决方法
  12. 60905一种六磁子交通系统
  13. html背景颜色渐变代码
  14. 手机的1G,2G,3G和4G区别识记
  15. 【第五届集创赛备赛】七、紫光同创李星钢和王斌赛题培训(2021年4月13日)
  16. idea怎么设置类备注和方法备注的格式
  17. 微信发朋友圈测试用例
  18. PHP根据身份证号码找出出生年月和判断男女
  19. JPA以外键为条件查询出的List(外键过滤并存入JSONObject)
  20. map方法的常见使用

热门文章

  1. javascript 检测浏览器版本号
  2. Android 软件盘弹出点击空白处键盘消失的方案
  3. DM365 adc学习笔记
  4. 教你轻松玩转-ChatGPT或生成类大模型--助你成为未来高端黄金职业人
  5. Could not execute auto check for display colors using command /usr/bin/xdpyinfo
  6. 相寻梦里路,飞雨落花中
  7. linux7磁盘文件类型,CentOS 7 查看磁盘文件系统格式
  8. 用Vue整合Echarts做数据展示:整合Echarts
  9. [漏洞利用]利用五次Shift越权破解win7\win10开机密码
  10. linux shell 学习笔记