本文采用 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