Flea-frame-db uses FleaJPAQuery to implement JPA sub-table query

Realization of JPA sub-table query based on FleaJPAQuery

This article uses EclipseLink's JPA implementation, please refer to my other blog posts for the access and use of FleaJPAQuery .

First, let’s discuss what we need to do in order to implement JPA sub-table query:

  • Definition of sub-table rules (that is, the realization of the conversion from the main table to the sub-table)
  • Sub-table query implementation (that is, the JPA standardized query component queries specific sub-tables according to sub-table rules)

JPA standardized query

In JPA, the table corresponding to the entity is defined by the following annotations:

@Entity
@Table(name = "flea_login_log")

As can be seen above, the entity class actually only corresponds to one table name, and the sub-table query cannot be realized from here alone.
Since the table cannot be divided in this way, we choose to go back and see when the table name is used by that object, because we can confirm that the last table name in the query must be the table name defined by the annotation used.
The following is the discovery of the debugging process:
com.huazie.frame.db.jpa.common.FleaJPAQuery

	/**
     * <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);
    }

The following two figures are the Debug view of the root SQL expression object Root. It is found that the DatabaseTable object stores the actual table name .
Insert picture description hereInsert picture description here
So now that the table name is actually related, the following focus is how to dynamically change the query table name in the process of using JPA standardized query. The solutions for the above-mentioned things we need to do are given below:

Definition of sub-table rules

The table name defined in the entity class can be understood as the main table name; the naming rule of the sub-table name needs to be determined first, and the following configuration is defined:

<?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>

For the implementation code related to the table splitting rule, you can move to GitHub to view TableSplitHelper

Sub-table query implementation

In the above definition of the sub-table rules, we can see that the sub-table name expression exp is composed of the main table name and sub-table fields, and the conversion implementation rules for sub-table fields are defined by 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 sub-table query related code can be moved to GitHub to view FleaJPAQuery and EclipseLinkTableSplitHandler ; self-test class can be viewed AuthTest .

Guess you like

Origin blog.csdn.net/u012855229/article/details/101295818