思路分为两步
一步是每月底自动创建下月的表,通过存储过程(创建表)和事件(定时调用存储过程)实现
第二步是项目中用mybatisPlus的DynamicTableNameInnerInterceptor拦截器对访问该表的数据库操作进行拦截,重新构建sql语句
创建存储过程示例:
DROP PROCEDURE
IF
EXISTS create_order_by_month;
CREATE DEFINER=`root`@`localhost` PROCEDURE `create_order_by_month`()
BEGIN
DECLARE
nextMonthStr VARCHAR ( 6 );
DECLARE
createStr VARCHAR ( 2000 );
SET @nextMonthStr = DATE_FORMAT( DATE_ADD( NOW(), INTERVAL 1 MONTH ), '%Y%m' );
SET @createStr = CONCAT( "CREATE TABLE `sms_order_", @nextMonthStr, "` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bc_id` int(11) DEFAULT NULL COMMENT '计费代码id,关联bc.id',
`user_mobile` varchar(11) DEFAULT NULL COMMENT '用户手机号',
`province` varchar(50) DEFAULT NULL COMMENT '省',
`order_no` varchar(25) DEFAULT NULL COMMENT '订单号',
`status` int(11) NOT NULL DEFAULT '0' COMMENT '用户订购状态:0 默认值,1 退订,2 订购,3 支付失败',
`status_desc` varchar(500) DEFAULT NULL COMMENT '状态描述',
`valid_code` varchar(10) DEFAULT NULL COMMENT '验证码',
`price` int(11) DEFAULT NULL COMMENT '价格(分)',
`imsi` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`imei` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`phone_model` varchar(50) DEFAULT NULL COMMENT '用户机型',
`pay_time` datetime DEFAULT NULL COMMENT '订购时间',
`cancel_time` datetime DEFAULT NULL COMMENT '退订时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uq_order_no` (`order_no`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='订单表';" );
PREPARE stmt
FROM
@createStr;
EXECUTE stmt;
END
创建事件定时调用建好的存储过程
-- 以$$作为分隔符
DELIMITER $$
SET GLOBAL event_scheduler = 1;
-- 事件名
CREATE EVENT event_create_table_every_month
-- 间隔一个月
ON SCHEDULE EVERY 1 MONTH
-- 第一次执行时间
STARTS date_add( LAST_DAY(CURDATE()), INTERVAL 0 HOUR )
ON COMPLETION PRESERVE
ENABLE
DO
BEGIN
-- 要调用的函数或者存储过程
CALL create_order_by_month();
END $$
-- 将分隔符重置为;
DELIMITER ;
至此数据库就会每个月自动创建下月的表了,这里设置的是每月最后一天零点创建下月的表
然后就是项目中的处理,实现动态查询当月的表
添加需要用到的依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
然后定义mbp的拦截类,实现根据传入订单号动态查询对应月份的订单表
package cn.com.ilives.smsnew.config;
import cn.com.ilives.smsnew.helper.RequestDataHelper;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
@Configuration
@MapperScan("cn.com.ilives.smsnew.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
if (StringUtils.isNotEmpty(tableName) && "sms_order".equals(tableName)) {
Map<String, Object> requestData = RequestDataHelper.getRequestData();
String orderNo = String.valueOf(requestData.get("orderNo"));
String tIndex = orderNo.substring(0, 6);
return tableName + "_" + tIndex;
}else {
return tableName;
}
});
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
return interceptor;
}
}
还有一个请求参数传递辅助类
package cn.com.ilives.smsnew.helper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import java.util.Map;
/**
* 请求参数传递辅助类
*/
public class RequestDataHelper {
/**
* 请求参数存取
*/
private static final ThreadLocal<Map<String, Object>> REQUEST_DATA = new ThreadLocal<>();
/**
* 设置请求参数
*
* @param requestData 请求参数 MAP 对象
*/
public static void setRequestData(Map<String, Object> requestData) {
REQUEST_DATA.set(requestData);
}
/**
* 获取请求参数
*
* @param param 请求参数
* @return 请求参数 MAP 对象
*/
public static <T> T getRequestData(String param) {
Map<String, Object> dataMap = getRequestData();
if (CollectionUtils.isNotEmpty(dataMap)) {
return (T) dataMap.get(param);
}
return null;
}
/**
* 获取请求参数
*
* @return 请求参数 MAP 对象
*/
public static Map<String, Object> getRequestData() {
return REQUEST_DATA.get();
}
}
业务层里会访问此表的方法,都用请求参数传递辅助类传递动态构建表名所需的参数。以此达到访问当月表的目的
@Override
public Integer saveOrder(Order order) {
// 就是这部分
RequestDataHelper.setRequestData(new HashMap<String, Object>() {{
put("orderNo", order.getOrderNo());
}});
// ————————————
return orderMapper.insert(order);
}
结束