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 {
//  省略代码,下面这是私有方法,大家可以往上找,看各方法的功能
 /**
     * <p>
     * 初始化 表主键,表字段
     * </p>
     *
     * @param clazz        实体类
     * @param globalConfig 全局配置
     * @param tableInfo    数据库表反射信息
     */
    private static void initTableFields(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo, List<String> excludeProperty) {
        /* 数据库全局配置 */
        GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
        Reflector reflector = tableInfo.getReflector();
        List<Field> list = getAllFields(clazz);
        // 标记是否读取到主键
        boolean isReadPK = false;
        // 是否存在 @TableId 注解
        boolean existTableId = isExistTableId(list);
        // 是否存在 @TableLogic 注解
        boolean existTableLogic = isExistTableLogic(list);

        List<TableFieldInfo> 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<TableFieldInfo> 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条件。

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值