Mybatis-Plus動態(tài)表名的實(shí)現(xiàn)示例
前言
在某些情況下,需要將大量數(shù)據(jù)分散到多個數(shù)據(jù)表中,這樣可以提高數(shù)據(jù)庫的查詢效率和數(shù)據(jù)處理能力。按天分表就是一種常見的數(shù)據(jù)分表策略,它將每天的數(shù)據(jù)放到一個獨(dú)立的數(shù)據(jù)表中,可以方便地進(jìn)行數(shù)據(jù)查詢和備份。但是,為了實(shí)現(xiàn)按天分表需要動態(tài)表名的支持,即在創(chuàng)建表時根據(jù)當(dāng)前日期自動生成表名。這樣可以確保每天數(shù)據(jù)都存放在不同的表中,避免數(shù)據(jù)重復(fù)或覆蓋的情況。同時,動態(tài)表名還可以幫助開發(fā)人員更方便地管理數(shù)據(jù),例如刪除過期數(shù)據(jù)表等。因此,使用動態(tài)表名是按天分表的必要條件之一。
例如:t_user_20230901、t_user_20230902、t_user_20230903…
一、方案一(動態(tài)傳參)
使用方法(Mapper自定義SQL)
坐標(biāo)依賴
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency>
數(shù)據(jù)源配置
spring: datasource: url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver
實(shí)體類
@Data @TableName("t_user") public class User { @TableId(type = IdType.AUTO) private Integer id; @TableField("name") private String name; }
這里的@TableName("t_user")映射表名不需要帶上日期后綴
Mapper
@Mapper public interface UserMapper extends BaseMapper<User> { // 方法1 @Select("Select * from ${tableName}") List<User> getUserInfo(@Param("tableName") String tableName); // 方法2 List<User> getUserInfoMP(String tableName); }
MapperXML
<?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.xx.xx.mapper.UserMapper"> <select id="getUserInfoMP" resultType="com.xx.xx.entity.User" > select * from ${tableName} order by phone_number ASC </select> </mapper>
具體使用
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; void query(){ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); String rDay = LocalDateTime.now().format(formatter); String tableName = "t_user_" + rDay; List<User> list1 = userMapper.getUserInfo(tableName); List<User> list2 = userMapper.getUserInfoMP(tableName); } }
二、方案二(DynamicTableNameInnerInterceptor插件)
使用方法(插件配置+ThreadLocal+輔助類)
配置類
@Configuration @MapperScan(basePackages = {"com.xx.**.mapper"}) public class MybatisPlusConfig { public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); //動態(tài)表名 DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor(); //可以傳多個表名參數(shù),指定哪些表使用DayTableNameHandler處理表名稱 dynamicTableNameInnerInterceptor.setTableNameHandler(new DayTableNameHandler("t_user")); //以攔截器的方式處理表名稱 //可以傳遞多個攔截器,即:可以傳遞多個表名處理器TableNameHandler mybatisPlusInterceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor); return mybatisPlusInterceptor; } }
輔助類
/** * 按天參數(shù),組成動態(tài)表名 */ public class DayTableNameHandler implements TableNameHandler { //用于記錄哪些表可以使用該動態(tài)表名處理器(即哪些表需要分表) private List<String> tableNames; //構(gòu)造函數(shù),構(gòu)造動態(tài)表名處理器的時候,傳遞tableNames參數(shù) public DayTableNameHandler(String ...tableNames) { this.tableNames = Arrays.asList(tableNames); } //每個請求線程維護(hù)一個day數(shù)據(jù),避免多線程數(shù)據(jù)沖突。所以使用ThreadLocal private static final ThreadLocal<String> DAY_DATA = new ThreadLocal<>(); //設(shè)置請求線程的day數(shù)據(jù) public static void setData(String day) { DAY_DATA.set(day); } //刪除當(dāng)前請求線程的day數(shù)據(jù) public static void removeData() { DAY_DATA.remove(); } //動態(tài)表名接口實(shí)現(xiàn)方法 @Override public String dynamicTableName(String sql, String tableName) { if (this.tableNames.contains(tableName)){ return tableName + "_" + DAY_DATA.get(); //表名增加后綴 }else{ return tableName; //表名原樣返回 } } }
具體使用
@Service public class UserServiceImpl implements UserService { @Autowired private UserService userService; void query(){ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); String rDay = LocalDateTime.now().format(formatter); DayTableNameHandler.setData(rDay); List<User> list = userService.list(); // 用完即銷毀 DayTableNameHandler.removeData(); } }
這里可以自行打印SQL語句驗(yàn)證 Select * from t_user_20230909
三、方案三(DynamicTableNameInnerInterceptor插件、省略輔助類)
這里可以直接配置DynamicTableNameInnerInterceptor插件做簡單的使用,但是用法相對固定,不能根據(jù)實(shí)際情況控制實(shí)體類所映射的表名,原因是被統(tǒng)一攔截
使用方法(插件配置+ThreadLocal)
配置類
@Configuration @MapperScan(basePackages = {"com.xx.**.mapper"}) public class MybatisPlusConfig { public static ThreadLocal<String> myTableName = new ThreadLocal<>(); public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); //動態(tài)表名 DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor(); HashMap<String, TableNameHandler> map = new HashMap<String, TableNameHandler>(2) {{ put("t_user", (sql, tableName) -> { return myTableName.get(); }); }}; dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map); mybatisPlusInterceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor); myTableName.remove(); return mybatisPlusInterceptor; } }
具體使用
@Service public class UserServiceImpl implements UserService { @Autowired private UserService userService; void query(){ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); String rDay = LocalDateTime.now().format(formatter); DayTableNameHandler.setData(rDay); String tableName = "t_user" + rDay; MybatisPlusConfig.myTableName.set(tableName); List<User> list = userService.list(); } }
總結(jié)
三種方法可以結(jié)合實(shí)際需要選擇,使用Mapper自定義SQL要注意SQL注入,使用線程池的方式要記得清理。
注意
Threadlocal 中的數(shù)據(jù)在AOP中最好自己釋放掉 ,spring是用的線程池,如果不清理掉會影響線程下次使用的程序。
到此這篇關(guān)于Mybatis-Plus動態(tài)表名的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Mybatis-Plus 動態(tài)表名內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot 使用 Swagger 構(gòu)建 RestAPI 接口文檔
這篇文章主要介紹了Spring Boot 使用 Swagger 構(gòu)建 RestAPI 接口文檔,幫助大家更好的理解和使用Spring Boot框架,感興趣的朋友可以了解下2020-10-10命令行中 javac、java、javap 的使用小結(jié)
使用 java 命令運(yùn)行一個.class文件,需要使用該類的全限定類名,同時需要在當(dāng)前路徑下有該類的包層次文件夾,這篇文章主要介紹了命令行中 javac、java、javap 的使用小結(jié),需要的朋友可以參考下2023-07-07Java設(shè)計(jì)模式之橋模式(Bridge模式)介紹
這篇文章主要介紹了Java設(shè)計(jì)模式之橋模式(Bridge模式)介紹,本文講解了為什么使用橋模式、如何實(shí)現(xiàn)橋模式、Bridge模式在EJB中的應(yīng)用等內(nèi)容,需要的朋友可以參考下2015-03-03SpringBoot從2.7.x 升級到3.3注意事項(xiàng)
從SpringBoot 2.7.x升級到3.3涉及多個重要變更,特別是因?yàn)?nbsp;Spring Boot 3.x 系列基于 Jakarta EE 9,而不再使用 Java EE,本文就來詳細(xì)的介紹一下,感興趣的可以了解一下2024-09-09SWT(JFace) Menu、Bar...體驗(yàn)代碼
SWT(JFace)體驗(yàn)之Menu、Bar實(shí)現(xiàn)代碼。2009-06-06