mybatis+mybatisplus源码学习(十一)逻辑删除TableLogic


前言

Mybatisplus自动注入的方法实现了逻辑删除,就是对数据做了一个删除标识,并没有真正的删除数据。


一、TableLogic的使用

(1)、配置文件中配置

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

(2)注解

在字段上加上注解@TableLogic,或者按照步骤1设置字段名logic-delete-field: flag,都会被当做逻辑删除字段,优先按照注解来判断

@TableLogic
private Integer deleted;

二、TableLogic的解析

(1)在注入Mybatisplus的自定义方法时,会初实体类的字段信息

AbstractSqlInjector

TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
 /* 初始化字段相关 */
 initTableFields(clazz, globalConfig, tableInfo, excludePropertyList);
 // 是否存在 @TableLogic 注解
 boolean existTableLogic = isExistTableLogic(list);
 //校验@TableLogic是否存在
 public static boolean isExistTableLogic(List<Field> list) {
     return list.stream().anyMatch(field -> field.isAnnotationPresent(TableLogic.class));
    }

(2)TableFieldInfo

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) {
            String deleteField = dbConfig.getLogicDeleteField();
            if (StringUtils.isNotBlank(deleteField) && this.property.equals(deleteField)) {
            	//不存在@TableLogic,并且当前字段与配置的逻辑删除字段一样
                this.logicNotDeleteValue = dbConfig.getLogicNotDeleteValue();
                this.logicDeleteValue = dbConfig.getLogicDeleteValue();
                this.logicDelete = true;
            }
        }
    }

三、逻辑删除sql

(1)DeleteById ,将删除语句转换成更新语句

update user set deleted=1 where id = 1 and deleted=0
public class DeleteById extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sql;
        //LOGIC_DELETE_BY_ID("deleteById", "根据ID 逻辑删除一条数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
        SqlMethod sqlMethod = SqlMethod.LOGIC_DELETE_BY_ID;
        if (tableInfo.isWithLogicDelete()) {
        	//获取逻辑删除sql
            sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), sqlLogicSet(tableInfo),
                tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),
                tableInfo.getLogicDeleteSql(true, true));
            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, Object.class);
            return addUpdateMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource);
        } else {
            sqlMethod = SqlMethod.DELETE_BY_ID;
            sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), tableInfo.getKeyColumn(),
                tableInfo.getKeyProperty());
            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, Object.class);
            return this.addDeleteMappedStatement(mapperClass, getMethod(sqlMethod), sqlSource);
        }
    }
}

(2)sqlLogicSet( )

将删除修改为更新语句,获取set片段

 protected String sqlLogicSet(TableInfo table) {
        return "SET " + table.getLogicDeleteSql(false, false);
    }

(3)getLogicDeleteSql( )

public String getLogicDeleteSql(boolean startWithAnd, boolean isWhere) {
        if (withLogicDelete) {
            String logicDeleteSql = formatLogicDeleteSql(isWhere);
            if (startWithAnd) {
                logicDeleteSql = " AND " + logicDeleteSql;
            }
            return logicDeleteSql;
        }
        return EMPTY;
    }

(4)formatLogicDeleteSql( )

private String formatLogicDeleteSql(boolean isWhere) {
		//根据where获取LogicNotDeleteValue或LogicDeleteValue
        final String value = isWhere ? logicDeleteFieldInfo.getLogicNotDeleteValue() : logicDeleteFieldInfo.getLogicDeleteValue();
        if (isWhere) {
            if (NULL.equalsIgnoreCase(value)) {
            	//处理 where 中null值
                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)) {
        	//处理不是where后面的语句的null值
            return targetStr + NULL;
        } else {
            return targetStr + String.format(logicDeleteFieldInfo.isCharSequence() ? "'%s'" : "%s", value);
        }
    }

四、逻辑查询sql

(1)SelectById ,拼接上逻辑删除字段条件

select id,name,deleted from user where deleted=0
public class SelectById extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        SqlMethod sqlMethod = SqlMethod.SELECT_BY_ID;
        SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(),
            sqlSelectColumns(tableInfo, false),
            tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),
            //这里获取逻辑删除条件
            tableInfo.getLogicDeleteSql(true, true)), Object.class);
        return this.addSelectMappedStatementForTable(mapperClass, getMethod(sqlMethod), sqlSource, tableInfo);
    }
}

五、逻辑更新sql

(1)UpdateById,set片段去除逻辑删除字段,value片段

update user set name='lisi',version=1 where id=1 and version=0 and deleted=0
public class UpdateById extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
    	// UPDATE_BY_ID("updateById", "根据ID 选择修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
        SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID;
        //处理乐观锁字段、逻辑删除字段
        final String additional = optlockVersion(tableInfo) + tableInfo.getLogicDeleteSql(true, true);
        String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(),
        	//处理set,并去除逻辑删除字段
            sqlSet(tableInfo.isWithLogicDelete(), false, tableInfo, false, ENTITY, ENTITY_DOT),
            tableInfo.getKeyColumn(), ENTITY_DOT + tableInfo.getKeyProperty(), additional);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return addUpdateMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource);
    }
}


总结

MybatisPlus提供了逻辑删除的功能,只能用于自动注入的方法,不能用于自定义方法;如果想让所有的sql生效,可以自定义mybatis的拦截器,在拦截器内实现修改sql的逻辑。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_lrs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值