mybatis实现分表

article/2025/10/27 18:01:50

分析上面登陆,当前表按照年份分表了,最大的一张表超过500w建议分表

 注意:之前写的经过多方测试发现遍历的时候参数传递不进去,现如今已经完善

package org.jeecg.config.mybatis;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.util.Date;
import java.util.Properties;/*** mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间** @Author scott* @Date 2019-01-19*/
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class MybatisAddCommonValuesInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();Object parameter = invocation.getArgs()[1];if (parameter == null) {return invocation.proceed();}if (SqlCommandType.INSERT == sqlCommandType) {LoginUser sysUser = this.getLoginUser();Field[] fields = oConvertUtils.getAllFields(parameter);for (Field field : fields) {try {if ("createBy".equals(field.getName())) {field.setAccessible(true);Object local_createBy = field.get(parameter);field.setAccessible(false);if (local_createBy == null || local_createBy.equals("")) {if (sysUser != null) {// 登录人账号field.setAccessible(true);field.set(parameter, sysUser.getUsername());field.setAccessible(false);}}}// 注入创建时间if ("createTime".equals(field.getName())) {field.setAccessible(true);Object local_createDate = field.get(parameter);field.setAccessible(false);if (local_createDate == null || local_createDate.equals("")) {field.setAccessible(true);field.set(parameter, new Date());field.setAccessible(false);}}//注入部门编码if ("sysOrgCode".equals(field.getName())) {field.setAccessible(true);Object local_sysOrgCode = field.get(parameter);field.setAccessible(false);if (local_sysOrgCode == null || local_sysOrgCode.equals("")) {// 获取登录用户信息if (sysUser != null) {field.setAccessible(true);field.set(parameter, sysUser.getOrgCode());field.setAccessible(false);}}}} catch (Exception e) {}}}if (SqlCommandType.UPDATE == sqlCommandType) {LoginUser sysUser = this.getLoginUser();Field[] fields = null;if (parameter instanceof ParamMap) {ParamMap<?> p = (ParamMap<?>) parameter;//update-begin-author:scott date:20190729 for:批量更新报错issues/IZA3Q--if (p.containsKey("et")) {parameter = p.get("et");} else {parameter = p.get("param1");}//update-end-author:scott date:20190729 for:批量更新报错issues/IZA3Q-//update-begin-author:scott date:20190729 for:更新指定字段时报错 issues/#516-if (parameter == null) {return invocation.proceed();}//update-end-author:scott date:20190729 for:更新指定字段时报错 issues/#516-fields = oConvertUtils.getAllFields(parameter);} else {fields = oConvertUtils.getAllFields(parameter);}for (Field field : fields) {log.debug("------field.name------" + field.getName());try {if ("updateBy".equals(field.getName())) {//获取登录用户信息if (sysUser != null) {// 登录账号field.setAccessible(true);field.set(parameter, sysUser.getUsername());field.setAccessible(false);}}if ("updateTime".equals(field.getName())) {field.setAccessible(true);field.set(parameter, new Date());field.setAccessible(false);}} catch (Exception e) {e.printStackTrace();}}}return invocation.proceed();}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// TODO Auto-generated method stub}//update-begin--Author:scott  Date:20191213 for:关于使用Quzrtz 开启线程任务, #465private LoginUser getLoginUser() {LoginUser sysUser = null;try {sysUser = SecurityUtils.getSubject().getPrincipal() != null ? (LoginUser) SecurityUtils.getSubject().getPrincipal() : null;} catch (Exception e) {//e.printStackTrace();sysUser = null;}return sysUser;}//update-end--Author:scott  Date:20191213 for:关于使用Quzrtz 开启线程任务, #465}

package org.jeecg.config.mybatis;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.jeecg.common.config.mqtoken.UserTokenContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.sql.Connection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;/*** @version 1.0* @Author zhaozhiqiang* @Date 2022/9/5 20:06* @Description //TODO  动态修改表名字*/
@Slf4j
@Component//@Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
//@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class })
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}
)
public class MybatisFixTableInterceptor implements Interceptor {private static RedisUtil redisUtil;private final static Map<String, String> TABLE_MAP = new LinkedHashMap<>();//动态配置需要拦截表/分表的名字@Value("${mybatis-interceptor.splipTables}")public void setSplipTables(String msplipTables) {// 获取执行的SQL参数String currentYears = DateUtils.getDate("yyyy");log.info("动态配置需要拦截表:{}", msplipTables);//表名长的放前面,避免字符串匹配的时候先匹配替换子集if (oConvertUtils.isNotEmpty(msplipTables)) {String[] permissionUrl = msplipTables.split(",");for (String table : permissionUrl) {TABLE_MAP.put(table, table + "_" + currentYears);}}log.info("动态配置需要拦截表集合为:{}", TABLE_MAP.size());}@Overridepublic Object intercept(Invocation invocation) throws Throwable {if( invocation.getTarget() instanceof  StatementHandler){//修改sqlif (null == redisUtil) {redisUtil = (RedisUtil) SpringContextUtils.getBean("redisUtil");}StatementHandler statementHandler = (StatementHandler) invocation.getTarget();MetaObject metaObject = MetaObject.forObject(statementHandler, new DefaultObjectFactory(),new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");// 获取执行的SQLString sql = boundSql.getSql();// 获取执行的SQL参数String token = UserTokenContext.getToken();if (isReplaceTableName(sql,token)) {String currentYears = "";if (StringUtils.isNotBlank(token)) {Object years = redisUtil.get(CommonConstant.PREFIX_LOGIN_YEAR + token);if (null != years) {currentYears = (String) years;}}for (Map.Entry<String, String> entry : TABLE_MAP.entrySet()) {log.debug("原sql:{}",sql);if (StringUtils.isNotBlank(currentYears)) {sql = sql.replace(entry.getKey(), entry.getKey() + "_" + currentYears);} else {sql = sql.replace(entry.getKey(), entry.getValue());}log.debug("后sql:{}",sql);}}// 替换执行的的SQL.metaObject.setValue("delegate.boundSql.sql", sql);MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");SqlCommandType sqlCommandType = ms.getSqlCommandType();if (sqlCommandType != SqlCommandType.UPDATE && sqlCommandType != SqlCommandType.INSERT) {return invocation.proceed();}}return invocation.proceed();}/**** 判断是否需要替换表名* @param sql* @return*/private boolean isReplaceTableName(String sql,String token) {String currentYears = "";if (StringUtils.isNotBlank(token)) {Object years = redisUtil.get(CommonConstant.PREFIX_LOGIN_YEAR + token);if (null != years) {currentYears = (String) years;}}for (String tableName : TABLE_MAP.keySet()) {//不能无限制递归替换if (StringUtils.isNotBlank(currentYears)) {if (sql.contains(tableName) && !sql.contains(tableName + "_" + currentYears)) {if(sql.split(tableName).length>1){//去除主子表,列如:item_type,itemboolean b = sql.split(tableName)[1].startsWith("_");if(b){return false;}}return true;}} else {if (sql.contains(tableName) && !sql.contains(TABLE_MAP.get(tableName))) {//!sql.split(tableName)[1].split("_")[0].split("\\s")[0].contains(currentYears)if(sql.split(tableName).length>1){boolean b = sql.split(tableName)[1].startsWith("_");if(b){//去除主子表,列如:item_type,itemreturn false;}}return true;}}}return false;}public static void main(String[] args) {String sql="select * from item_type";String tableName="item";String currentYears="2023";boolean test = test(sql, tableName, currentYears);System.out.println(test);}public  static boolean test(String sql,String tableName,String currentYears){if (sql.contains(tableName) && !sql.contains(tableName + "_" + currentYears)) {if(sql.split(tableName).length>1){String str= sql.split(tableName)[1].split("_")[0].split("\\s")[0];if(str.contains(currentYears)){return true;}return false;}return true;}return false;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// TODO Auto-generated method stub// 赋值成员变量,在其他方法使用
//        this.properties = properties;}}

在yml中配置要分表的信息

#mybatis拦截分表配置,多个都好隔开
mybatis-interceptor:splipTables: pe_regist_detail_item,pe_result,pe_lis_return_data

注意:因为年表是从前端传递过来的,和登录token是一个级别,如果涉及多线程操作表的时候需要重新传递token,不然年表找不到,解决方案如下

 前端传递过来的token级别的年表需要在登录接口中缓存到redis中

 


http://chatgpt.dhexx.cn/article/Jj2ENStG.shtml

相关文章

mysql 分表条件_mysql分表详解

本人混迹qq群2年多了&#xff0c;经常听到有人说“数据表太大了&#xff0c;需要分表”&#xff0c;“xxxx了&#xff0c;要分表”的言论&#xff0c;那么&#xff0c;到底为什么要分表&#xff1f; 难道数据量大就要分表&#xff1f; mysql数据量对索引的影响 本人mysql版本为…

ShardingSphere简介与分表使用

一、ShardingSphere简介 1、简介 ShardingSphere 已于 2020 年 4 月 16 日成为 Apache 软件基金会的顶级项目。 ShardingSphere 是一套开源的分布式数据库中间件解决方案。 ShardingSphere 产品定位为 Database Plus&#xff0c;旨在构建异构数据库上层的标准和生态圈。 它…

mysql mybatis分表查询_mybatis 自动分表

参考: 相关源码已上传至我的 github 欢迎转载,转载请注明出处,尊重作者劳动成果:https://www.cnblogs.com/li-mzx/p/9963312.html 前言 小弟才疏学浅,可能很多问题也没有考虑到,权当抛砖引玉,希望各位大神指点 项目背景: 希望做一个功能,能在sql操作数据库时,根据某个…

mysql 分区分表_mysql分库分区分表

一、分表 分表分为水平分表和垂直分表。 水平分表原理&#xff1a; 分表策略通常是用户ID取模&#xff0c;如果不是整数&#xff0c;可以首先将其进行hash获取到整。 水平分表遇到的问题&#xff1a; 1. 跨表直接连接查询无法进行 2. 我们需要统计数据的时候 3. 如果数据…

Mock平台介绍

Mock平台可以用来模拟接口&#xff0c;具备了get方法&#xff0c;post方法&#xff0c;header&#xff0c;cookie&#xff0c;重定向等功能。 Mock平台的搭建应用于mock框架&#xff0c;在github上可以下载到开源的代码。 下载地址&#xff1a;http://repo1.maven.org/maven2/…

Mock 框架 Moq 的使用

Intro# Moq 是 .NET 中一个很流vb.net教程行的 Mock 框架&#xff0c;使c#教程用 Mock 框架我python基础教程们可以只针对我java基础教程们关注的代码进行测试&#xff0c;对于sql教程依赖项使用 Mock 对象配置预期的依赖服务的行为。 Moq 是基于 Castle 的动态代理来实现的&…

mockjs入门

mockjs 1,mock.js是什么&#xff1f; mockjs是生成随机数据的一款前端工具&#xff0c;用来模拟 Ajax 请求&#xff0c;生成并返回模拟数据 2&#xff0c;为什么用mockjs&#xff1f; 当程序员做项目开发时&#xff0c;前端工程师要请求后端做好的数据时&#xff0c;有可能…

monkey简介

https://blog.csdn.net/lebang08/article/details/70858532 https://www.cnblogs.com/aland-1415/p/6949964.html https://blog.csdn.net/aisemi/article/details/55254348 一、Monkey 简介 monkey是Android SDK中自带的一个命令行工具&#xff0c;使用Java语言写成&#xf…

mokey的介绍和使用

一、monkey介绍 monkey是Android SDK提供的一个命令行工具&#xff0c;可以简单方便的发送伪随机的用户时间流&#xff0c;对Android APP做压力&#xff08;稳定性、健壮性&#xff09;测试。主要是为了测试APP是否存在无响应和崩溃的情况。 二、monkey的使用 1、前提条件&a…

APP测试— 测试工具mokey

文章目录 1 Mokey概念2 运行Monkey&#xff08;对手机进行300次无规律点击&#xff09;3 Mokey常规参数4 Monkey 事件类参数5 Monkey 约束类参数 1 Mokey概念 1&#xff09;Monkey是Android SDK提供的一个命令行工具&#xff0c;可以简单、方便的运行任何版本的Android模拟器和…

Kafka配置用户名密码访问

1 软件版本 kafka_2.12-2.4.0.tgz&#xff08;带zookeeper&#xff09; 2 kafka服务端部署 2.1 将安装包上传到服务器&#xff0c;并解压 tar zxvf kafka_2.12-2.4.0.tgz -C /datamv kafka_2.12-2.4.0 kafka2.2 修改kafka配置文件 server.properties vim /data/kafka/conf…

linux 用户名和密码的处理

1. 创建新用户和密码 # 创建用户 testuser useradd testuser# 给已创建的用户testuser设置密码 passwd testuser# 新创建的用户会在 /home 下创建一个用户目录testuser# 修改用户这个命令的相关参数 usermod --help# 删除用户testuser userdel testuser# 删除用户所在目录rm -…

用户名,密码登录

1.导入项目需要的依赖&#xff0c;分层 注意&#xff1a;如果你的数据库是5.5的版本&#xff0c;依赖要用低版本的&#xff0c;高版本不稳定&#xff0c;新增的内容不识别&#xff0c;会报各种各样奇葩的错误 2.创建实体类 它的属性要和数据库字段对应 package com.oa.entity…

实现用户输入用户名和密码登录

题目 实现用户输入用户名和密码登录&#xff0c;当用户名为admin或administrator且密码为666666时&#xff0c;显示“登录成功”&#xff0c;否则显示“登录失败”&#xff0c;登录失败时允许重复输入三次。 实例 参考程序 User1 "admin" User2 "administr…

计算机用户名和初始密码,电脑默认的用户名和密码是多少

优质回答 回答者&#xff1a;止树2018 电脑用户默认是没有密码的&#xff0c;除非你设置了&#xff0c;没有设置的前提下&#xff0c;直接按回车键就可以进系统了。 电脑默认的用户是administrator&#xff0c;如果你创建了自己的新用户名&#xff0c;那么&#xff0c;原始管理…

服务器密码以及用户名怎么修改

服务器密码以及用户名怎么修改 我是艾西&#xff0c;今天给大家说下服务器密码如何修改 windows2003系统&#xff1a; 1、右键我的电脑&#xff0c;点击“管理”&#xff1a; 2、在“本地用户和组”中打开“用户”&#xff0c;在右侧找到 Administrator 账户进行修改。 200…

电脑更改开机密码和用户名

一、电脑更改开机密码 1、快捷键CtrlAltDel出现以下界面。 2、点击“更改密码”&#xff0c;出现修改密码的界面&#xff0c;输入旧的密码&#xff0c;以及新的密码&#xff0c;确定即可。 二、电脑更改开机用户名 1、打开电脑的”控制面板“。 2、在控制面板中点击“用户帐户…

基于51单片机的呼吸灯程序编写

利用51单片机编写的呼吸灯小程序&#xff0c;实验程序内容截图分享~

六、Arduino呼吸灯的实现

实验所需材料 Arduino UNO面包板LED灯一个330Ω电阻一个 连接示意图 如图所示&#xff0c;实验中我们将LED连接到了带PWM功能的D9引脚。 可以在 Arduino IDE菜单>文件>示例>03.Analog>Fading 打开呼吸灯示例程序&#xff0c;程序如下&#xff1a; int ledPin 9…

C语言实现呼吸灯(HAL库)

1. 呼吸灯原理 呼吸灯的实现可以通过控制灯的亮度连续变化&#xff0c;当变化的频率大于24帧时&#xff0c;肉眼看上去就会逐渐变暗&#xff0c;逐渐变亮。 2. PWM控制亮度 PWM通过设置亮度在一段时间内的占空比&#xff0c;亮的百分比多&#xff0c;人眼看到的就亮&#xf…