2. 如何让mybatis-plus的逻辑删除注解@TableLogic临时失效

如何让mybatis-plus的逻辑删除注解@TableLogic临时失效

1. 场景复现

1.1 controller代码

@GetMapping("/getSpacexTable")
public String getSpacexTable(){
    List<SpacexTable> list = spacexTableService.queryAll();
    return JSON.toJSONString(list);
}

1.2 service层代码

@Override
public List<SpacexTable> queryAll() {
    List<SpacexTable> list = list();
    return list;
}

1.3 entity代码

@Data
@TableName(value ="spacex_table")
public class SpacexTable implements Serializable {
    @TableId
    private String id;
    private String name;
    @TableLogic
    private Integer isDel;
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

2. 问题分析

当我们正常调用接口时,sql查询日志为

SELECT id,name,is_del FROM spacex_table WHERE is_del=0

数据库数据记录为:
在这里插入图片描述
接口调用结果为

[{"id":"1","isDel":0,"name":"小张"},{"id":"3","isDel":0,"name":"小杨"}]

可见逻辑删除注解已生效,is_del=1的小李没有查询出来

3. 解决方案

3.1 说明

  1. 我们让当前查询的逻辑删除失效时,不应影响其他查询活动,所以我们我们需要在线程上打上标识,区分是否执行逻辑删除
  2. 因为使用了mybatis-plus框架,所以可以通过拦截器来实现,在适当方法处,将sql语句中的逻辑删除替换掉即可

3.2 核心代码

@Slf4j
@Component
// 拦截StatementHandler的prepare方法,改变编译的SQL语句
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class LogicDeletenterceptor implements Interceptor {
    
    // 通过ThreadLocal给当前线程打上标识
    public static ThreadLocal<Boolean> logicDelete = new ThreadLocal();
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.info("====SqlModifyInterceptor======(" + logicDelete.get() + ")=====");
        // 判断线程标识
        if (!Boolean.FALSE.equals(logicDelete.get())) {
            return invocation.proceed();
        }
        StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
            return invocation.proceed();
        }
        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
        String sql = boundSql.getSql();
        log.info("origin sql:" + sql);
        // TODO 在这里替换字段,改成不影响结果的条件即可
        sql = sql.replace("is_del=0","1=1").replace("del_number=0", "1=1");
        metaObject.setValue("delegate.boundSql.sql",sql);
        log.info("modify sql:" + sql);
        return invocation.proceed();
    }
    
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {}
}

3.3 service方法对应修改为

@Override
public List<SpacexTable> queryAll() {
    // 开启逻辑删除失效    
    LogicDeletenterceptor.logicDelete.set(false);
    List<SpacexTable> list = list();
    // 关闭逻辑删除失效
    LogicDeletenterceptor.logicDelete.remove();
    return list;
}

3.4 运行结果

sql查询日志为

SELECT id,name,is_del FROM spacex_table WHERE 1=1

接口调用结果为

[{"id":"1","isDel":0,"name":"小张"},{"id":"2","isDel":1,"name":"小李"},{"id":"3","isDel":0,"name":"小杨"}]

可见逻辑删除is_del=1的小李也被查询出来了

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-06 05:48:11       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-06 05:48:11       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-06 05:48:11       87 阅读
  4. Python语言-面向对象

    2024-04-06 05:48:11       96 阅读

热门阅读

  1. 数学专题2 -最大公约数和最小公倍数

    2024-04-06 05:48:11       33 阅读
  2. LeetCode热题Hot100 - 盛水最多的容器

    2024-04-06 05:48:11       42 阅读
  3. WebKit结构简介

    2024-04-06 05:48:11       42 阅读
  4. sqlmap基础知识(三)

    2024-04-06 05:48:11       41 阅读
  5. 信创咨询岗位需求分析

    2024-04-06 05:48:11       36 阅读
  6. Hibernate中的ORM(对象关系映射)是如何工作的?

    2024-04-06 05:48:11       35 阅读
  7. 苹果公司为什么要设计元类

    2024-04-06 05:48:11       38 阅读
  8. 类和对象(二)

    2024-04-06 05:48:11       36 阅读