mybatis-plus查询sql条件拼接deleted = 0

本文介绍springboot整合mybatis-plus在项目中使用时,写查询方法的时候,使用lambda表示查询数据,在真正执行sql的时候where条件会拼接deleted = 0 。

原因:1、全局配置配置删除字段。默认删除值=1.未删除值=0。配置方式如下:

mybatis-plus.global-config.db-config.logic-delete-field = deleted

在使用全局配置的时候,如果实体类中有deleted字段,就会拼接deleted = 0.

2. 如果全局没有配置,在实体类中单独使用代码

@Data
@Accessors(chain = true)
@TableName("order")
public class Order {

    @ApiModelProperty(value = "主键ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @TableLogic(value = "0",delval = "1")
    @ApiModelProperty(value = "是否已删除, 1:是, 0:否")
    private Integer deleted;

}

这也可以生效,如果,想灵活使用deleted = 0 ,自己决定是否在查询中拼接deleted = 0。那么就不能使用全局配置,自己在查询时,如果实体类中逻辑删除字段,就会拼接,没有就不会拼接,执行删除的时候,也需要自己设置deleted 的值。

源码分析:

代码1

public class TableInfoHelper {
//  省略代码,下面这是私有方法,大家可以往上找,看各方法的功能
 /**
     * 

* 初始化 表主键,表字段 *

* * @param clazz 实体类 * @param globalConfig 全局配置 * @param tableInfo 数据库表反射信息 */ private static void initTableFields(Class clazz, GlobalConfig globalConfig, TableInfo tableInfo, List excludeProperty) { /* 数据库全局配置 */ GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig(); Reflector reflector = tableInfo.getReflector(); List list = getAllFields(clazz); // 标记是否读取到主键 boolean isReadPK = false; // 是否存在 @TableId 注解 boolean existTableId = isExistTableId(list); // 是否存在 @TableLogic 注解 boolean existTableLogic = isExistTableLogic(list); List fieldList = new ArrayList<>(list.size()); for (Field field : list) { if (excludeProperty.contains(field.getName())) { continue; } // 该字段是否是主键,默认FALSE,下面赋值 boolean isPK = false; boolean isOrderBy = field.getAnnotation(OrderBy.class) != null; /* 主键ID 初始化 */ if (existTableId) { TableId tableId = field.getAnnotation(TableId.class); if (tableId != null) { if (isReadPK) { throw ExceptionUtils.mpe("@TableId can't more than one in Class: \"%s\".", clazz.getName()); } // 有主键,设置主键生成方法,主键名字 initTableIdWithAnnotation(dbConfig, tableInfo, field, tableId); // 这只是主键为true isPK = isReadPK = true; } } else if (!isReadPK) { isPK = isReadPK = initTableIdWithoutAnnotation(dbConfig, tableInfo, field); } if (isPK) { if (isOrderBy) { tableInfo.getOrderByFields().add(new TableFieldInfo(dbConfig, tableInfo, field, reflector, existTableLogic, true)); } continue; } final TableField tableField = field.getAnnotation(TableField.class); /* 有 @TableField 注解的字段初始化 */ if (tableField != null) { // 注意看new TableFieldInfo()这个构造方法,执行的时候,会判断字段是否有@TableLogic注解,没有,看全局配置, // existTableLogic这个参数是整个实体类中是否有@TableLogic注解 fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field, tableField, reflector, existTableLogic, isOrderBy)); continue; } /* 无 @TableField 注解的字段初始化 */ fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field, reflector, existTableLogic, isOrderBy)); } /* 字段列表 */ tableInfo.setFieldList(fieldList); /* 未发现主键注解,提示警告信息 */ if (!isReadPK) { logger.warn(String.format("Can not find table primary key in Class: \"%s\".", clazz.getName())); } } }

看代码

new TableFieldInfo(dbConfig, tableInfo, field, reflector, existTableLogic, isOrderBy)

这个TableFieldInfo构造方法中,会调用this(...),在调用

this.initLogicDelete(dbConfig, field, existTableLogic);

代码2

private void initLogicDelete(GlobalConfig.DbConfig dbConfig, Field field, boolean existTableLogic) {
        /* 获取注解属性,逻辑处理字段 */
        TableLogic tableLogic = field.getAnnotation(TableLogic.class);
        if (null != tableLogic) {
            if (StringUtils.isNotBlank(tableLogic.value())) {
                this.logicNotDeleteValue = tableLogic.value();
            } else {
                this.logicNotDeleteValue = dbConfig.getLogicNotDeleteValue();
            }
            if (StringUtils.isNotBlank(tableLogic.delval())) {
                this.logicDeleteValue = tableLogic.delval();
            } else {
                this.logicDeleteValue = dbConfig.getLogicDeleteValue();
            }
            this.logicDelete = true;
        } else if (!existTableLogic) {
// 实体类中没有标记TableLogic注解,existTableLogic这个值=false,!existTableLogic=true,就会进入这个方法
            String deleteField = dbConfig.getLogicDeleteField();
// 上边获取全局的删除字段名称
// 下面判断字段名称和全局定义的一样,就赋值
            if (StringUtils.isNotBlank(deleteField) && this.property.equals(deleteField)) {
                this.logicNotDeleteValue = dbConfig.getLogicNotDeleteValue();
                this.logicDeleteValue = dbConfig.getLogicDeleteValue();
                this.logicDelete = true;
            }
        }
    }

在代码1方法中,tableInfo.setFieldList(fieldList);这行代码会调用tableInfo类的方法,

代码3

void setFieldList(List fieldList) {
        this.fieldList = fieldList;
        AtomicInteger logicDeleted = new AtomicInteger();
        AtomicInteger version = new AtomicInteger();
        fieldList.forEach(i -> {
// 在上边代码2中删除字段的isLogicDelete会赋值true
            if (i.isLogicDelete()) {
// 这里会设置withLogicDelete=true,
                this.withLogicDelete = true;
// 设置删除字段
                this.logicDeleteFieldInfo = i;
                logicDeleted.getAndAdd(1);
            }
            if (i.isWithInsertFill()) {
                this.withInsertFill = true;
            }
            if (i.isWithUpdateFill()) {
                this.withUpdateFill = true;
            }
            if (i.isOrderBy()) {
                if (null == this.orderByFields) {
                    this.orderByFields = new LinkedList<>();
                }
                this.orderByFields.add(i);
            }
            if (i.isVersion()) {
                this.withVersion = true;
                this.versionFieldInfo = i;
                version.getAndAdd(1);
            }
        });
        /* 校验字段合法性 */
        Assert.isTrue(logicDeleted.get() <= 1, "@TableLogic not support more than one in Class: \"%s\"", entityType.getName());
        Assert.isTrue(version.get() <= 1, "@Version not support more than one in Class: \"%s\"", entityType.getName());
    }

等调用查询方法的时候,拼接sql时会调用

public class TableInfo{
 /**
     * 获取逻辑删除字段的 sql 脚本
     *
     * @param startWithAnd 是否以 and 开头
     * @param isWhere      是否需要的是逻辑删除值
     * @return sql 脚本
     */
    public String getLogicDeleteSql(boolean startWithAnd, boolean isWhere) {
// 如果类中有删除字段,标记了@TableLogic注解,或者字段和全局一样,withLogicDelete在代码3中已经
// 赋值=true,就会进入下面的拼接deleted = 0 方法
        if (withLogicDelete) {
            String logicDeleteSql = formatLogicDeleteSql(isWhere);
            if (startWithAnd) {
                logicDeleteSql = " AND " + logicDeleteSql;
            }
            return logicDeleteSql;
        }
        return EMPTY;
    }

    /**
     * format logic delete SQL, can be overrided by subclass
     * github #1386
     *
     * @param isWhere true: logicDeleteValue, false: logicNotDeleteValue
     * @return sql
     */
// 真正拼接的方法
    protected String formatLogicDeleteSql(boolean isWhere) {
        final String value = isWhere ? logicDeleteFieldInfo.getLogicNotDeleteValue() : logicDeleteFieldInfo.getLogicDeleteValue();
        if (isWhere) {
            if (NULL.equalsIgnoreCase(value)) {
                return logicDeleteFieldInfo.getColumn() + " IS NULL";
            } else {
                return logicDeleteFieldInfo.getColumn() + EQUALS + String.format(logicDeleteFieldInfo.isCharSequence() ? "'%s'" : "%s", value);
            }
        }
        final String targetStr = logicDeleteFieldInfo.getColumn() + EQUALS;
        if (NULL.equalsIgnoreCase(value)) {
            return targetStr + NULL;
        } else {
            return targetStr + String.format(logicDeleteFieldInfo.isCharSequence() ? "'%s'" : "%s", value);
        }
    }
}

如果在查询的sql中想不拼接deleted = 0 ,解决方法:

1. 不设置全局逻辑删除字段,如果有逻辑删除,自己在代码中定义删除字段,并标记@TableLogic注解,里面可以写删除的值,和不删除的值。如果设置全局删除字段,适用于,删除场景比较少,查询比较的多的。并且项目中采用的是逻辑删除。

2.如果设置了全局的删除字段,实体类中定义的删除字段与全局的不一样。如果自己在那个字段上加@TableLogic注解,代码查询就会拼接删除=0条件,不加注解,就自己设置。

3. 如果项目查询比较多,都是采用逻辑删除,在查询的时候需要查出删除数据,就需要自己写xml的sql语句。其他lambda表达式的查询,由mybatis自动加上deleted = 0条件。

你可能感兴趣的:(mybatis-plus学习,sql,spring,boot,java)