笔者也是从昨天才入手的mp,今天在解决逻辑删除的问题上绕了好久,由于官方文档上的逻辑删除确实只给出了Integer的实现,而很多orm的框架的软删除支持delete_time等在时间上的赋值,为了跟以前的项目保持统一,却又不想重新实现一遍logic的所有方法,因此提供了下面的方法来实现delete_time的赋值问题,希望帮助更多的开发者,如果已经有人也是这样实现的,纯属雷同。
经过我半天的探索和研究,增加delete_time的方式如下:
- 添加逻辑删除注解
@Getter
@Setter
@ToString
public class User {
private Long id;
private String name;
private Integer age;
private String email;
@TableLogic
private Date deleteTime;
}
- 修改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,帮助更多的开发者,拜谢了,确实又很多人在这个问题上绕了很久。
Comment From: whh945atsyzx
好神奇的方案...这样子逻辑删除不会失效?
Comment From: pedrogao
就目前使用的情况是没有失效的
Comment From: qmdx
Very well modified to closed state
Comment From: 5468sun
在我这不管用 MYSQL 删除时执行如下sql: UPDATE wms_mgr_permission SET delete_time=NOW() WHERE guid=1145120443882397698 AND delete_time=NULL
应为 delete_time is NULL
Comment From: pedrogao
抱歉,确实是有问题的,我这边也发现了,后续再找找其它方法吧
Comment From: pedrogao
还是通过黑魔法解决了一下,毕竟为了兼容,推荐新项目就不要这么做了,通过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,笔者也是因为项目的原因才这样做,慎用。
Comment From: yuxiaobin
别用黑科技了,这个问题已经修复 参考提交
稍后发一个快照可以先用着
Comment From: pedrogao
喜大普奔,发版了就不用了黑魔法了
Comment From: yuxiaobin
快照已发,请配置快照仓库并使用版本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>
Comment From: 5468sun
坐等发版
Comment From: zonasgao
升版了 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'
Comment From: YiuTerran
这里用UNIX_TIMESTAMP(),然后default 0不是更简单么,无须null
Comment From: maybeyj
这里用UNIX_TIMESTAMP(),然后default 0不是更简单么,无须null
用UNIX_TIMESTAMP(),如果【批量删除】岂不是会有问题?
Comment From: liuanxin
默认值设置成 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.已删除',
Comment From: MccRay-s
默认值设置成 0, 删除的时候设置成当前时间戳
yaml mybatis-plus.global-config.db-config: logic-delete-field: isDeleted logic-delete-value: UNIX_TIMESTAMP() logic-not-delete-value: 0如果不想用上面的全局配置(比如有些表可能不需要用唯一索引, 字段用 0 1 就够了), 就在具体的注解上处理
```java /* 删除标识: 0.未删除, 非 0.删除 --> is_deleted / @TableLogic(value = "0", delval = "UNIX_TIMESTAMP()") private Integer isDeleted;
或者
/* 删除标识: 0.未删除, 1.已删除 --> is_deleted / @TableLogic private Boolean isDeleted; ```
上面的两种分别对应有唯一索引和没有的情况
``sqlis_deletedINT NOT NULL DEFAULT '0' COMMENT '删除标识: 0.未删除, 非 0.删除', UNIQUE INDEXuk_xxx(xxx,is_deleted`),或者
is_deletedTINYINT(1) NOT NULL DEFAULT '0' COMMENT '删除标识: 0.未删除, 1.已删除', ```
nice 一直没有尝试,然后就在找方法,看到老哥的办法直接尝试了一下OK了
Comment From: KANLON
一般 delete_time 设置为 0000-00-00 00:00:00 这个合适些? 这样在表有唯一索引的时候,不会因为delete_time 为null,而导致唯一索引不生效
Comment From: langlichong
写了个TableInfo的子类覆盖了formatLogicDeleteSql,程序启动后做业务查询压根不会执行到子类覆盖的代码,要做额外的配置吗(spring boot web环境)
Comment From: Wuaner
写了个TableInfo的子类覆盖了formatLogicDeleteSql,程序启动后做业务查询压根不会执行到子类覆盖的代码,要做额外的配置吗(spring boot web环境)
用不了。注释估计是瞎写的
Comment From: leechor
mysql, 列采用tinyint(1),默认为1,
logic-delete-field: is_actual
logic-delete-value: "NULL"
logic-not-delete-value: 1
因为mysql把NULL索引当做唯一值,跟他组成联合索引后这样也可以保证被删除的记录不冲突。同时一般都有update_time,可以表示删除时间。