Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于逻辑删除的 delete_time 问题,不是issue,只是帮助贴,望海涵。 #1386

Closed
pedrogao opened this issue Jul 17, 2019 · 19 comments

Comments

@pedrogao
Copy link

笔者也是从昨天才入手的mp,今天在解决逻辑删除的问题上绕了好久,由于官方文档上的逻辑删除确实只给出了Integer的实现,而很多orm的框架的软删除支持delete_time等在时间上的赋值,为了跟以前的项目保持统一,却又不想重新实现一遍logic的所有方法,因此提供了下面的方法来实现delete_time的赋值问题,希望帮助更多的开发者,如果已经有人也是这样实现的,纯属雷同。

经过我半天的探索和研究,增加delete_time的方式如下:

  1. 添加逻辑删除注解
@Getter
@Setter
@ToString
public class User {

    private Long id;

    private String name;

    private Integer age;

    private String email;

    @TableLogic
    private Date deleteTime;
}
  1. 修改appplication.properties配置
# mybatis.mapper-locations=classpath:mapper/*.xml
# mybatis.type-aliases-package=com.pedro.shirodemo.mapper
mybatis-plus.configuration.map-underscore-to-camel-case=true
# 逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=NOW()
mybatis-plus.global-config.db-config.logic-not-delete-value=NULL

此处比较取巧,因为delete-value和not-delete-value均为字符串值,sql在拼接的时候也会拼字符串,因此完全可以借助sql自身的 NOW() 函数来实现delete_time的赋值。

希望可以开此issue,帮助更多的开发者,拜谢了,确实又很多人在这个问题上绕了很久。

@whh945atsyzx
Copy link

好神奇的方案...这样子逻辑删除不会失效?

@pedrogao
Copy link
Author

就目前使用的情况是没有失效的

@qmdx
Copy link
Member

qmdx commented Jul 18, 2019

Very well modified to closed state

@qmdx qmdx closed this as completed Jul 18, 2019
@5468sun
Copy link

5468sun commented Jul 21, 2019

在我这不管用
MYSQL
删除时执行如下sql:
UPDATE wms_mgr_permission SET delete_time=NOW() WHERE guid=1145120443882397698 AND delete_time=NULL

应为 delete_time is NULL

@pedrogao
Copy link
Author

抱歉,确实是有问题的,我这边也发现了,后续再找找其它方法吧

@pedrogao
Copy link
Author

还是通过黑魔法解决了一下,毕竟为了兼容,推荐新项目就不要这么做了,通过mybatis的拦截器,修改原始的sql语句,如下:

package com.lin.cms.demo.common.mybatis;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
@Slf4j
public class LogicInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
        //获取到原始sql语句
        String sql = boundSql.getSql();
        if (sql.contains("delete_time=NULL")){
            String mSql = sql.replace("delete_time=NULL","delete_time is NULL");
            //通过反射修改sql语句
            Field field = boundSql.getClass().getDeclaredField("sql");
            field.setAccessible(true);
            field.set(boundSql, mSql);
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

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

delete_time=NULL通过拦截器修改为了delete_time is NULL,这样的做法比较hack,不知道会不会有后面的bug,笔者也是因为项目的原因才这样做,慎用。

@yuxiaobin
Copy link
Contributor

别用黑科技了,这个问题已经修复
参考提交

稍后发一个快照可以先用着

@pedrogao
Copy link
Author

喜大普奔,发版了就不用了黑魔法了

@yuxiaobin
Copy link
Contributor

快照已发,请配置快照仓库并使用版本3.1.3.1-SNAPSHOT

<repository>
<id>snapshot</id>
<name>mp-snapshot</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>

<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.1.3.1-SNAPSHOT</version>

@5468sun
Copy link

5468sun commented Jul 23, 2019

坐等发版

@zonasgao
Copy link

升版了 3.2.0 之后已经可以这样使用了,首先感谢各位大佬们方案和支持。
同时提出自己遇到的一个小坑给各位参考:
环境:springboot 2.1.0.RELEASE,使用yaml进行配置解析。
问题:在通过yaml使用配置 mybatis-plus.global-config.db-config.logic-not-delete-value=NULL 的时候SQL附带的添加为查询条件为 deleted=,后面就没有了,所以一直报错。
原因:因为使用yaml进行配置文件解析的时候会自动转换成空字符串
解决:将配置更改为
mybatis-plus:
global-config:
db-config:
logic-not-delete-value: 'NULL'

@YiuTerran
Copy link

这里用UNIX_TIMESTAMP(),然后default 0不是更简单么,无须null

@maybeyj
Copy link

maybeyj commented Oct 21, 2020

这里用UNIX_TIMESTAMP(),然后default 0不是更简单么,无须null

用UNIX_TIMESTAMP(),如果【批量删除】岂不是会有问题?

@liuanxin
Copy link

liuanxin commented Feb 24, 2021

默认值设置成 0, 删除的时候设置成当前时间戳

mybatis-plus.global-config.db-config:
  logic-delete-field: isDeleted
  logic-delete-value: UNIX_TIMESTAMP()
  logic-not-delete-value: 0

如果不想用上面的全局配置(比如有些表可能不需要用唯一索引, 字段用 0 1 就够了), 就在具体的注解上处理

/** 删除标识: 0.未删除, 非 0.删除 --> is_deleted */
@TableLogic(value = "0", delval = "UNIX_TIMESTAMP()")
private Integer isDeleted;

或者

/** 删除标识: 0.未删除, 1.已删除 --> is_deleted */
@TableLogic
private Boolean isDeleted;

上面的两种分别对应有唯一索引和没有的情况

`is_deleted` INT NOT NULL DEFAULT '0' COMMENT '删除标识: 0.未删除, 非 0.删除',
UNIQUE INDEX `uk_xxx` (`xxx`, `is_deleted`),

或者

`is_deleted` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '删除标识: 0.未删除, 1.已删除',

@MccRay-s
Copy link

MccRay-s commented Apr 2, 2022

默认值设置成 0, 删除的时候设置成当前时间戳

mybatis-plus.global-config.db-config:
  logic-delete-field: isDeleted
  logic-delete-value: UNIX_TIMESTAMP()
  logic-not-delete-value: 0

如果不想用上面的全局配置(比如有些表可能不需要用唯一索引, 字段用 0 1 就够了), 就在具体的注解上处理

/** 删除标识: 0.未删除, 非 0.删除 --> is_deleted */
@TableLogic(value = "0", delval = "UNIX_TIMESTAMP()")
private Integer isDeleted;

或者

/** 删除标识: 0.未删除, 1.已删除 --> is_deleted */
@TableLogic
private Boolean isDeleted;

上面的两种分别对应有唯一索引和没有的情况

`is_deleted` INT NOT NULL DEFAULT '0' COMMENT '删除标识: 0.未删除, 非 0.删除',
UNIQUE INDEX `uk_xxx` (`xxx`, `is_deleted`),

或者

`is_deleted` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '删除标识: 0.未删除, 1.已删除',

nice 一直没有尝试,然后就在找方法,看到老哥的办法直接尝试了一下OK了

@KANLON
Copy link

KANLON commented Jan 17, 2023

一般 delete_time 设置为 0000-00-00 00:00:00 这个合适些? 这样在表有唯一索引的时候,不会因为delete_time 为null,而导致唯一索引不生效

@langlichong
Copy link

langlichong commented Jan 3, 2024

image
写了个TableInfo的子类覆盖了formatLogicDeleteSql,程序启动后做业务查询压根不会执行到子类覆盖的代码,要做额外的配置吗(spring boot web环境)

@Wuaner
Copy link

Wuaner commented Feb 1, 2024

image 写了个TableInfo的子类覆盖了formatLogicDeleteSql,程序启动后做业务查询压根不会执行到子类覆盖的代码,要做额外的配置吗(spring boot web环境)

用不了。注释估计是瞎写的

@leechor
Copy link

leechor commented Jun 11, 2024

mysql, 列采用tinyint(1),默认为1,

      logic-delete-field: is_actual
      logic-delete-value: "NULL"
      logic-not-delete-value: 1

因为mysql把NULL索引当做唯一值,跟他组成联合索引后这样也可以保证被删除的记录不冲突。同时一般都有update_time,可以表示删除时间。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests