本文采用 EclipseLink的JPA實現,相關FleaJPAQuery的接入使用請移步個人另外幾篇博文。html
首先討論一下,爲了實現JPA分表查詢,咱們須要作哪些事情:java
在JPA中,實體對應的表由以下的註解定義:git
@Entity @Table(name = "flea_login_log")
如上可見,實體類實際上只會對應一個表名,單純從這裏是沒法實現分表查詢。
那麼既然這樣沒法分表,咱們選擇退而求其次,看看錶名是何時,被那個對象使用,由於咱們能夠確認查詢最後的表名,必定是使用的註解定義的表名。
下面是調試過程的發現:
com.huazie.frame.db.jpa.common.FleaJPAQuerygithub
/** * <p> Flea JPA查詢對象池獲取以後,必定要調用該方法進行初始化 </p> * * @param entityManager JPA中用於增刪改查的接口 * @param sourceClazz 實體類類對象 * @param resultClazz 操做結果類類對象 * @since 1.0.0 */ public void init(EntityManager entityManager, Class sourceClazz, Class resultClazz) { this.entityManager = entityManager; this.sourceClazz = sourceClazz; this.resultClazz = resultClazz; // 從持久化接口中獲取標準化生成器 criteriaBuilder = entityManager.getCriteriaBuilder(); // 經過標準化生成器 獲取 標準化查詢對象 if (ObjectUtils.isEmpty(resultClazz)) { // 行記錄查詢結果 criteriaQuery = criteriaBuilder.createQuery(sourceClazz); } else { // 單個查詢結果 criteriaQuery = criteriaBuilder.createQuery(resultClazz); } // 經過標準化查詢對象,獲取根SQL表達式對象 root = criteriaQuery.from(sourceClazz); }
以下兩張圖是根SQL表達式對象 Root 的Debug視圖,發現存儲實際表名的是 DatabaseTable 對象。
那麼既然找到了表名實際相關的地方,下面的重點就是如何在使用的JPA標準化查詢的過程當中,動態改變查詢的表名。下面給出上述咱們須要作的事情的解決方案:ide
實體類中定義的表名,咱們能夠理解爲主表名;分表名的命名規則首先須要肯定一下,定義以下配置:ui
<?xml version="1.0" encoding="UTF-8"?> <tables> <!-- 定義分表配置 name : 分表對應的主表名 exp : 分表名錶達式 (FLEA_TABLE_NAME)_(列名大寫)_(列名大寫) --> <table name="flea_login_log" exp="(FLEA_TABLE_NAME)_(CREATE_DATE)" desc="Flea登陸日誌表分表規則"> <splits> <!-- 定義分表後綴 key : 分表類型關鍵字 (可查看 com.huazie.frame.db.common.table.split.TableSplitEnum ) column : 分表屬性列字段名 implClass : 分表後綴轉換實現類 --> <split key="yyyymm" column="create_date" implClass="com.huazie.frame.db.common.table.split.impl.YYYYMMTableSplitImpl"/> </splits> </table> </tables>
分表規則相關實現代碼,能夠移步 GitHub 查看 TableSplitHelperthis
在上述分表規則定義中, 咱們能夠看到分表名錶達式exp是由 主表名 和 分表字段 組成,分表字段的轉換實現規則由split定義。調試
@Override public void handle(CriteriaQuery criteriaQuery, Object entity) throws Exception { if (ObjectUtils.isEmpty(criteriaQuery) || ObjectUtils.isEmpty(entity)) { return; } // 獲取分表信息(包括主表名 和 分表名 【若是存在分表返回】) SplitTable splitTable = EntityUtils.getSplitTable(entity); // 存在分表,須要查詢指定分表 if (StringUtils.isNotBlank(splitTable.getSplitTableName())) { Set<Root<?>> roots = criteriaQuery.getRoots(); if (CollectionUtils.isNotEmpty(roots)) { // 從新設置 查詢的分表表名 ((EntityTypeImpl<?>) roots.toArray(new Root<?>[0])[0].getModel()).getDescriptor().setTableName(splitTable.getSplitTableName()); } } }
JPA分表查詢相關代碼能夠 移步 GitHub 查看 FleaJPAQuery 和 EclipseLinkTableSplitHandler;日誌
自測類能夠查看 AuthTest。code