mybatis-plus 動態表名
一:背景
我們在查詢數據庫設計的時候會按一定的條件分表,我們需要根據條件拼接動態表名
在動態分表的背景下,有時候查詢數據的時候需要跨表查詢,那此時就需要MP在解析的時候,能夠很好的自適應表格名稱,進行wrapper條件查詢
二:實現
MP中是通過PaginationInterceptor(分頁插件)完成動態表名解析的,最終用法如下:
DynamicTableTreadLocal.INSTANCE.setTableName(GcQmUtil.getCartNumberByCartNumber(cartNumber)); QueryWrapper<QmRectifySlave> wrapper = new QueryWrapper<>();
三:pom.xml 依賴
<mybatis-plus-boot-starter.version>3.3.1</mybatis-plus-boot-starter.version> <!-- mybatis-plus begin --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus-boot-starter.version}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>${mybatis-plus-boot-starter.version}</version> </dependency>
四:配置類
package com.kexin.common.config; import com.baomidou.mybatisplus.extension.incrementer.OracleKeyGenerator; import com.baomidou.mybatisplus.extension.parsers.DynamicTableNameParser; import com.baomidou.mybatisplus.extension.parsers.ITableNameHandler; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringBootConfiguration; import org.springframework.context.annotation.Bean; import java.util.Collections; import java.util.HashMap; @SpringBootConfiguration @MapperScan("com.kexin.admin.mapper*") public class MybatisPlusConfig { private static final String DYNAMIC_TABLE_PRE = "QM_RECTIFY_SLAVE"; @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 設置請求的頁面大於最大頁后操作, true調回到首頁,false 繼續請求 默認false // paginationInterceptor.setOverflow(false); // 設置最大單頁限制數量,默認 500 條,-1 不受限制 // paginationInterceptor.setLimit(500); // 開啟 count 的 join 優化,只針對部分 left join paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); // paginationInterceptor.setDbType("oracle"); // 設置請求的頁面大於最大頁后操作, true調回到首頁,false 繼續請求 默認false paginationInterceptor.setOverflow(false); // 設置最大單頁限制數量,默認 500 條,-1 不受限制 paginationInterceptor.setLimit(500); // // 開啟 count 的 join 優化,只針對部分 left join paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser(); dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, ITableNameHandler>(2) {{ //動態表規則-生成自己需要的動態表名 put(DYNAMIC_TABLE_PRE, (metaObject, sql, tableName) -> DynamicTableTreadLocal.INSTANCE.getTableName()); }}); paginationInterceptor.setSqlParserList(Collections.singletonList(dynamicTableNameParser)); return paginationInterceptor; } /** * Sequence主鍵自增 * * @return 返回oracle自增類 * @author * @date 2019/1/2 */ @Bean public OracleKeyGenerator oracleKeyGenerator(){ return new OracleKeyGenerator(); } }
五:動態表名存儲類
package com.kexin.common.config; /** * @description: 動態表名存儲類 * @author: 巫恆強 * @time: 2021/7/22 10:32 */ public enum DynamicTableTreadLocal { INSTANCE; private ThreadLocal<String> tableName = new ThreadLocal<>(); public String getTableName() { return tableName.get(); } public void setTableName(String tableName) { this.tableName.set(tableName); } public void remove() { tableName.remove(); } }
六:工具類 (根據實際情況編寫)
package com.kexin.common.util.gc; import com.kexin.admin.entity.tables.QmRectifyMaster; /** * @description: * @author: 巫恆強 * @time: 2021/7/15 14:24 */ public class GcQmUtil { public static String getCartNumberByRectifyMater(QmRectifyMaster master){ return "QM_RECTIFY_SLAVE_"+master.getCartNumber().substring(0,2); } public static String getCartNumberByCartNumber(String cartNumber){ return "QM_RECTIFY_SLAVE_"+cartNumber.substring(0,2); } }
七:具體使用 (分頁動態查詢)
DynamicTableTreadLocal.INSTANCE.setTableName(GcQmUtil.getCartNumberByCartNumber(cartNumber)); QueryWrapper<QmRectifySlave> wrapper = new QueryWrapper<>(); wrapper.eq("RECTIFYM_ID",rectifymId); IPage<QmRectifySlave> ipage = qmRectifySlaveService.page(new Page<>(page,limit),wrapper);
八:其他 原理
- 以mybatis的query方法作為入口
- 通過動態代理執行到配置的分頁插件
- 通過分頁插件進行sql解析
- 根據分頁插件中配置的tableNameHandler進行目標表格的替換
- 最后形成一個可執行sql,執行查詢