All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.bootx.table.modify.mysql.service.MySqlIndexInfoService Maven / Gradle / Ivy

There is a newer version: 1.5.5
Show newest version
package cn.bootx.table.modify.mysql.service;

import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndexes;
import cn.bootx.table.modify.mysql.constants.MySqlIndexType;
import cn.bootx.table.modify.mysql.entity.MySqlEntityIndex;
import cn.bootx.table.modify.mysql.entity.MySqlModifyMap;
import cn.bootx.table.modify.mysql.entity.MySqlTableIndex;
import cn.bootx.table.modify.mysql.handler.MySqlTableModifyDao;
import cn.bootx.table.modify.mysql.util.MySqlInfoUtil;
import cn.bootx.table.modify.utils.ClassUtils;
import cn.bootx.table.modify.utils.ColumnUtils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * MySQL索引处理
 * @author xxm
 * @since 2023/4/13
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MySqlIndexInfoService {
    private final MySqlTableModifyDao mySqlTableModifyDao;

    /**
     * 获取创建表锁需要的索引 不包括主键索引
     * @param clas 实体类
     * @param baseTableMap 用于存储各种操作MySQL表结构的容器
     */
    public void getCreateIndex(Class clas, MySqlModifyMap baseTableMap){
        // 获取entity的tableName
        String tableName = ColumnUtils.getTableName(clas);
        // 找出实体类所有的索引
        List entityIndexes = getEntityIndexes(clas);
        if (CollUtil.isNotEmpty(entityIndexes)) {
            baseTableMap.getAddIndexes().put(tableName, entityIndexes);
        }
    }

    /**
     * 获取要进行变动的的索引信息 不包括主键索引
     * @param clas 实体类
     * @param baseTableMap 用于存储各种操作MySQL表结构的容器
     */
    public void getModifyIndex(Class clas, MySqlModifyMap baseTableMap){

        // 是否追加模式
        boolean append = ColumnUtils.isAppend(clas);

        // 获取entity的tableName
        String tableName = ColumnUtils.getTableName(clas);

        // 找出实体类所有的索引
        List entityIndexes = getEntityIndexes(clas);

        // 查询当前表中全部索引
        List tableIndexes = mySqlTableModifyDao.findIndexByTableName(tableName);

        // 找出需要删除的索引, 追加模式不进行删除
        List dropIndexes = getDropIndexes(tableIndexes, entityIndexes);
        if (CollUtil.isNotEmpty(dropIndexes)&&!append) {
            baseTableMap.getDropIndexes().put(tableName, dropIndexes);
        }
        // 找出需要新增的索引
        List addIndexes = getAddIndexes(tableIndexes, entityIndexes);
        if (CollUtil.isNotEmpty(addIndexes)) {
            baseTableMap.getAddIndexes().put(tableName, addIndexes);
        }
        // 找出需要修改的索引
        List updateIndexes = getUpdateIndexes(tableIndexes, entityIndexes);
        if (CollUtil.isNotEmpty(updateIndexes)) {
            baseTableMap.getUpdateIndexes().put(tableName, updateIndexes);
        }
    }


    /**
     * 找出需要新建的索引 不包括主键索引
     * @param tableIndexes 当前数据库的索引
     * @param entityIndexes entity中的所有字段
     * @return 需要新建的索引
     */
    private List getAddIndexes(List tableIndexes, List entityIndexes) {
        if (CollUtil.isEmpty(entityIndexes)) {
            return new ArrayList<>(0);
        }
        List allIndexNames = tableIndexes.stream()
                .map(MySqlTableIndex::getIndexName)
                .distinct()
                .collect(Collectors.toList());

        return entityIndexes.stream()
                .filter(index->!allIndexNames.contains(index.getName()))
                .collect(Collectors.toList());
    }

    /**
     * 找出需要删除的索引
     * @param tableIndexes 当前数据库的索引
     * @param entityIndexes entity中所有配置的索引
     * @return 需要删除的索引名称
     */
    private List getDropIndexes(List tableIndexes, List entityIndexes) {
        if (CollUtil.isEmpty(tableIndexes)) {
            return new ArrayList<>(0);
        }

        // 定义的索引名称集合
        List entityIndexNames = entityIndexes.stream()
                .map(MySqlEntityIndex::getName)
                .map(String::toLowerCase)
                .distinct()
                .collect(Collectors.toList());
        // 将要删除的索引筛选出来
        return tableIndexes.stream()
                .map(MySqlTableIndex::getIndexName)
                .filter(indexName-> !entityIndexNames.contains(indexName.toLowerCase()))
                .distinct()
                .collect(Collectors.toList());

    }

    /**
     * 找出需要更新的索引
     * @param tableIndexes 当前数据库的索引
     * @param entityIndexes entity中的所有字段
     * @return 需要新建的索引
     */
    private List getUpdateIndexes(List tableIndexes, List entityIndexes) {
        if (CollUtil.isEmpty(entityIndexes)) {
            return new ArrayList<>(0);
        }
        // 现有的数据库索引配置
        List tableIndexNames = tableIndexes.stream()
                .map(MySqlTableIndex::getIndexName)
                .map(String::toLowerCase)
                .distinct()
                .collect(Collectors.toList());

        // 现有的数据库索引配置 MAP
        val tableIndexMap = tableIndexes.stream()
                .collect(Collectors.groupingBy(index -> index.getIndexName().toLowerCase()));

        // 把两者都有的索引筛选出来进行对比
        return entityIndexes.stream()
                .filter(index->tableIndexNames.contains(index.getName().toLowerCase()))
                .filter(entityIndex->compareIndex(tableIndexMap.get(entityIndex.getName().toLowerCase()),entityIndex))
                .collect(Collectors.toList());
    }

    /**
     * 比对索引类型
     */
    private boolean compareIndex(List tableIndex, MySqlEntityIndex entityIndex){
        MySqlTableIndex tableIndexInfo = tableIndex.get(0);

        /*
            获取现有的索引类型
            普通索引: non_unique: 1 index_type: BTREE
            全文索引: index_type: FULLTEXT
            唯一索引: non_unique: 0 index_type: BTREE
         */

        // 比对类型
        MySqlIndexType indexType = getIndexType(tableIndexInfo);
        if (indexType != entityIndex.getType()){
            return false;
        }

        // 比对索引字段
        tableIndex.sort(Comparator.comparing(MySqlTableIndex::getSeqInIndex));
        String tableColumnNames = tableIndex.stream()
                .map(MySqlTableIndex::getColumnName)
                .map(String::toLowerCase)
                .collect(Collectors.joining(","));
        String entityColumnNames = entityIndex.getColumns().stream()
                .map(String::toLowerCase)
                .collect(Collectors.joining(","));
        if (!Objects.equals(tableColumnNames,entityColumnNames)){
            return false;
        }

        // 比对索引备注
        if (!Objects.equals(tableIndexInfo.getIndexComment(),entityIndex.getComment())){
            return false;
        }
        return true;
    }

    /**
     * 获取索引类型
     */
    private MySqlIndexType getIndexType(MySqlTableIndex indexInfo) {
        if (Objects.equals(indexInfo.getIndexType(),"SPATIAL")){
            return MySqlIndexType.SPATIAL;
        }
        if (Objects.equals(indexInfo.getIndexType(), "BTREE") && !indexInfo.isNonUnique()) {
            return MySqlIndexType.NORMAL;
        }
        else if(Objects.equals(indexInfo.getIndexType(), "BTREE") && indexInfo.isNonUnique()){
            return MySqlIndexType.UNIQUE;
        } else {
            return MySqlIndexType.FULLTEXT;
        }
    }

    /**
     * 获取实体类配置的索引
     * 首先获取实体类上创建的索引, 如果不存在, 获取字段上配置的索引
     */
    private List getEntityIndexes(Class clas){

        // 多个索引注释处理
        List indexList = Optional.ofNullable(clas.getAnnotation(DbMySqlIndexes.class))
                .map(DbMySqlIndexes::value)
                .map(ListUtil::of)
                .orElse(new ArrayList<>(0));
        if (CollUtil.isEmpty(indexList)) {
            // 单个注解处理
            DbMySqlIndex dbMySqlIndex = clas.getAnnotation(DbMySqlIndex.class);
            if (Objects.nonNull(dbMySqlIndex)){
                indexList = ListUtil.of(dbMySqlIndex);
            }
        }
        // 返回处理完的索引配置
        if (CollUtil.isNotEmpty(indexList)) {
            return indexList.stream()
                    .map(index -> {
                        List columns = null;
                        // 先取数据库字段名配置
                        if (Objects.nonNull(index.columns())){
                            columns = Arrays.asList(index.columns());
                        }
                        // 不存在取实体类字段配置
                        if (CollUtil.isEmpty(columns)){
                            columns = getIndexColumnName(index.fields(),clas);
                        }
                        // 如果还为空. 抛出错误
                        if (CollUtil.isEmpty(columns)){
                            throw new RuntimeException("索引字段配置为空");
                        }
                        return new MySqlEntityIndex()
                                .setType(index.type())
                                .setName(MySqlInfoUtil.getIndexName(index,columns))
                                .setColumns(columns)
                                .setComment(index.comment());
                    })
                    .collect(Collectors.toList());
        } else {
            return getSimpleIndexes(clas);
        }

    }

    /**
     * 获取实体类字段对应的数据库表字段名称
     */
    private List getIndexColumnName(String[] fields,Class clas){
        return Arrays.stream(fields)
                .map(fieldName->{
                    // 转换成mtm的字段名
                    Field field = ClassUtils.getField(clas, fieldName);
                    return ColumnUtils.getColumnName(field,clas);
                }).collect(Collectors.toList());
    }

    /**
     * 获取字段上配置的简单索引方式
     */
    private List getSimpleIndexes(Class clas){
        // 实体类上未声明索引, 开始遍历字段找到索引配置, 进行简单索引方式处理
        Field[] fields = clas.getDeclaredFields();
        fields = ClassUtils.recursionParents(clas, fields);
        return Arrays.stream(fields).map(field->{
                    DbMySqlIndex index = field.getAnnotation(DbMySqlIndex.class);
                    if (Objects.isNull(index)){
                        return null;
                    }
                    MySqlEntityIndex mySqlEntityIndex = new MySqlEntityIndex()
                            .setType(index.type());
                    // 字段
                    String columnName = ColumnUtils.getColumnName(field, clas);
                    mySqlEntityIndex.setColumns(Collections.singletonList(columnName));
                    // 名称
                    if (StrUtil.isNotBlank(index.name())){
                        mySqlEntityIndex.setName(index.name());
                    } else {
                        mySqlEntityIndex.setName(columnName);
                    }
                    // 注释
                    if (StrUtil.isNotBlank(index.comment())){
                        mySqlEntityIndex.setComment(index.comment());
                    }
                    return mySqlEntityIndex;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy