Mybatis-Plus動態(tài)表名的實現(xiàn)示例
前言
在某些情況下,需要將大量數(shù)據(jù)分散到多個數(shù)據(jù)表中,這樣可以提高數(shù)據(jù)庫的查詢效率和數(shù)據(jù)處理能力。按天分表就是一種常見的數(shù)據(jù)分表策略,它將每天的數(shù)據(jù)放到一個獨立的數(shù)據(jù)表中,可以方便地進行數(shù)據(jù)查詢和備份。但是,為了實現(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)
坐標依賴
<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
實體類
@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);
}
//每個請求線程維護一個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)表名接口實現(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語句驗證 Select * from t_user_20230909
三、方案三(DynamicTableNameInnerInterceptor插件、省略輔助類)
這里可以直接配置DynamicTableNameInnerInterceptor插件做簡單的使用,但是用法相對固定,不能根據(jù)實際情況控制實體類所映射的表名,原因是被統(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é)合實際需要選擇,使用Mapper自定義SQL要注意SQL注入,使用線程池的方式要記得清理。
注意
Threadlocal 中的數(shù)據(jù)在AOP中最好自己釋放掉 ,spring是用的線程池,如果不清理掉會影響線程下次使用的程序。
到此這篇關(guān)于Mybatis-Plus動態(tài)表名的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)Mybatis-Plus 動態(tài)表名內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Jpa 如何使用@EntityListeners 實現(xiàn)實體對象的自動賦值
這篇文章主要介紹了Jpa 如何使用@EntityListeners 實現(xiàn)實體對象的自動賦值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
springboot v2.0.3版本多數(shù)據(jù)源配置方法
這篇文章主要介紹了springboot v2.0.3版本多數(shù)據(jù)源配置方法,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下2018-11-11
SpringCloudAlibaba Nacos開啟鑒權(quán)解決跳過登錄頁面問題
對于Nacos,如果需要開啟權(quán)限控制,可以在 Nacos 控制臺上進行配置,本文主要介紹了SpringCloudAlibaba Nacos開啟鑒權(quán)解決跳過登錄頁面問題,感興趣的可以了解一下2023-10-10
java通過HttpServletRequest獲取post請求中的body內(nèi)容的方法
本篇文章主要介紹了java通過HttpServletRequest獲取post請求中的body內(nèi)容的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02

