mysql逻辑删除案例_实现数据逻辑删除的一种方案

mysql逻辑删除案例_实现数据逻辑删除的一种方案什么是逻辑删除所谓逻辑删除是指数据已经“不需要”了,但是并没有使用delete语句将这些数据真实的从数据库中删除,而只是用一个标志位将其设置为已经删除。为什么需要逻辑删除对数据进行逻辑删除,一般存在以下原因:防止数据误删除,不能找回数据;这些数据还具有一定的商业价值,比如用户的注册信息;虽然这些数据可以删除,但是这些数据还有关联数据,这些关联数据不能删除。对数据进行逻辑删除,可以保证数据的安全性和…

大家好,又见面了,我是你们的朋友全栈君。

什么是逻辑删除

所谓逻辑删除是指数据已经“不需要”了,但是并没有使用delete语句将这些数据真实的从数据库中删除,而只是用一个标志位将其设置为已经删除。

3c5d19c2c11dc774fbf36128491e81a0.png

为什么需要逻辑删除

对数据进行逻辑删除,一般存在以下原因:

防止数据误删除,不能找回数据;

这些数据还具有一定的商业价值,比如用户的注册信息;

虽然这些数据可以删除,但是这些数据还有关联数据,这些关联数据不能删除。

对数据进行逻辑删除,可以保证数据的安全性和完整性。但是,逻辑删除也会带来的一些问题:

数据库表的数据冗余,导致查询缓慢;

写sql进行数据处理时需要排除那些已经逻辑删除的数据,这就会导致sql复杂,容易出错,特别是涉及多表查询时;

进行逻辑删除时,还需要考虑与之相关的数据怎么处理;

还有,如果数据表的某个字段要求唯一,并强制约束,比如用户表中的登录用户名字段,设计为逻辑删除的话,一旦有新的同用户名记录就无法插入。但如果不将该字段设置为唯一性约束的,那么在每次插入数据的时候,都需先进行一次查询,看看有无未(逻辑)删除的同名记录存在,低效率是一回事,而且在高并发的系统中,很难保证其正确性。

所以是否需要对数据进行逻辑删除,需要根据具体的业务场景,以及逻辑删除的优缺点进行综合考虑。

网友的一些建议

综合考虑,对于中小型的项目,逻辑删除所带来的好处有限,但带来的问题却很多。如果平时做好数据备份工作,还是可以预防物理删除隐患的。但心里应该清除,当项目大到一定程度,对数据安全性的要求高到一定程度,使用逻辑删除代替物理删除是必然的,在后面的数据库设计中,可以先小范围的尝试使用逻辑删除,一旦开发模式成熟,就全面使用逻辑删除代替物理删除。

逻辑删除怎么设计

设计方案一:在表中加一个字段deleted字段

deleted字段的值为0表示数据未删除,值为1表示数据已经删除。

插入数据数据时,这个值默认为0。删除数据时将这个值设置为1。查询和更新数据时都将‘deleted=0’这个条件带上,只查询和更新没有删除的数据。

这个方案比较简单,但是会有些问题。比如说你表中的一个字段user_name设置了唯一性约束,但是如果你只是进行了逻辑删除的话,相同的user_name就不能进行数据插入了。

但如果不将该字段设置为唯一性约束的,那么在每次插入数据的时候,都需先进行一次查询,看看有无未(逻辑)删除的同名记录存在,低效率是一回事,而且在高并发的系统中,很难保证其正确性。

abf1e0a01a88919b350a01ee26f053ed.png

然而你的服务运行了一段时间后你还是发现了数据库中存在 name = a 且 is_delete = 0 的多条字段,大部分是由于以下原因(并发问题):

91edc6c3e33926ec4b2d362aab164a04.png

这个问题有下面两个解决方案:

解决方案1:为数据库添加新的一列delete_token,当某一条记录需要删除时,将该字段设置为一个UUID,将name、delete_token设置为唯一键,这样当is_delete=0时,delete_token保持一个默认值,能够有效地限制name唯一,当记录被删除时,由于delete_token是一个唯一的UUID,便能保证删除的记录不会被唯一约束束缚。但正如该文章的博主所说,UUID会占用很大的空间,所以不推荐使用。评论网友针对该问题提出优化对策:将删除记录的delete_token设置为该记录的id。

个人认为,索引太大只是其中一个弊端,该方法还会面临一个很棘手的问题:当需要批量删除时,需要对每一条记录进行逐行删除。例如该表还有一个字段叫age,现在需要删除age > 18的记录,共有50条,在业务中,由于需要为每条的delete_token字段插入一个UUID所以需要将其拆分为50条更新操作来进行。这样的代价显然很难接受。

解决方案2:将删除标记设置默认值(例如0),将唯一字段与删除标记添加唯一键约束。当某一记录需要删除时,将删除标记置为NULL。

由于NULL不会和其他字段有组合唯一键的效果,所以当记录被删除时(删除标记被置为NULL时),解除了唯一键的约束。此外该方法能很好地解决批量删除的问题(只要置为NULL就完事了),消耗的空间也并不多(1位 + 联合索引)。

设计方案一:表备份

将删除的数据备份到其他备份表再进行删除。如果有级联数据,也需要进行删除备份。不然数据的完整性就不存在了。

使用MyBatis-Plus实现逻辑删除

这边,我们使用MyBatis-Plus的逻辑删除功能来实现下上面介绍的方案一。

MyBatis-Plus(简称MP)是对MyBatis的增强,可以完全兼容MyBatis的原生功能,而且几乎可以省略单表操作的所有增删改查方法,大大提升了开发效率。详细的使用方式可以参考官网

下面就来介绍下,MP的逻辑删除功能。

step1:进行配置

mybatis-plus:

global-config:

db-config:

# 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)

# logic-delete-field: flag

# 逻辑已删除值(默认为 1)

logic-delete-value: 1

# 逻辑未删除值(默认为 0)

logic-not-delete-value: 0

step2: 添加注解

@TableLogic()

@TableField(select = false)

private Integer deleted;

step3: 使用

@Test

public void apiTest(){

// UPDATE test.user SET deleted=1 WHERE user_id=? AND deleted=0

logger.info(“开始逻辑删除”);

int count = userDAO.deleteById(356);

// SELECT * FROM test.user WHERE user_id=? AND deleted=0

logger.info(“开始查询”);

User user = userDAO.selectById(357);

// UPDATE test.user SET user_name=?, telephone_no=?, id_card_no=?, identity_type=?, sex=?, birth_date=?, marital_status=?, asset_code=?, asset_branch_code=?, issuing_authority=?, job_type=?, address=?, work_unit=?, create_time=? WHERE user_id=? AND deleted=0

logger.info(“开始更新”);

userDAO.updateById(user);

}

MP的逻辑删除功能使用起来非常简单。但是需要我们注意以下几点:

开启逻辑删除功能后,MP在删除、查询和更新时会自动加上条件deleted=0,也就是只对没有删除的数据进行操作;

虽然MP对开启逻辑删除的表的插入操作没什么限制,但是还是建议在建表时,对deleted字段做默认限制,默认为0(未删除),插入数据时这个值可以不用设置;

对于自己在xml文件中定义的接口方法,MP是不会自动对其开启逻辑删除功能的,需要我们自己维护逻辑删除功能;

查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段;

下面是使用 QueryWrapper进行查询时的sql,我们发现前面的deleted=0条件会让后面我们自己加的deleted条件失效

SELECT * FROM test.user WHERE deleted=0 AND (user_id = ? AND deleted = ? AND user_name = ?)

追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段,原因和上面的原因是一样的。

参考

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/137315.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 彻底理解js中的闭包

    彻底理解js中的闭包闭包是js的一个难点也是它的一个特色,是我们必须掌握的js高级特性,那么什么是闭包呢?它又有什么用呢?我们都知道,js的作用域分两种,全局和局部,基于我们所熟悉的作用域链相关知识,我们知道在js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量并且可以获得当前包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的…

    2022年6月24日
    24
  • 牛腩新闻公布系统小结

    牛腩新闻公布系统小结

    2022年1月27日
    47
  • 姿态估计与行为识别(行为检测、行为分类)的区别[通俗易懂]

    姿态估计与行为识别(行为检测、行为分类)的区别[通俗易懂]姿态估计和行为识别作为计算机视觉的两个领域,对于新人来说,较为容易弄混姿态估计和行为识别两个概念。 姿态估计(PoseEstimation)是指检测图像和视频中的人物形象的计算机视觉技术,可以确定某人的某个身体部位出现在图像中的位置,也就是在图像和视频中对人体关节的定位问题,也可以理解为在所有关节姿势的空间中搜索特定姿势。简言之,姿态估计的任务就是重建人的关节和肢干,其难点主要在于…

    2022年6月21日
    28
  • visual studio community 2019激活_visual studio 2019社区版安装教程

    visual studio community 2019激活_visual studio 2019社区版安装教程VS2019社区版是免费的,但是需要登录微软账户,不登录只能使用30天,30天之后就无法使用了,如下图:首先使用能够访问外网的电脑登录微软账户注册VS。也可以使用我这个Licensing,直接进入第三步 找到注册文件,路径:C:\Users\{系统登录用户}\AppData\Local\Microsoft\VSCommon 将两个文件夹复制到需要注册的电脑上,路径:C:\…

    2022年8月22日
    24
  • 启动mysql报错10038_解决navicat远程连接mysql报错10038的问题

    navicat远程连接mysql报错10038一般由以下两个原因:一:本地防火墙问题在本地安装了mysql、navicat并打开了mysql服务的情况下,来设置防火墙。首先右击或者点击入站规则,找到新建规则,点击。点击端口。在特定本地端口中填入3306.一直点击下一步。这里可以给一个好分别的名称即可。之前再尝试连接即可,若仍然不可以,可能是服务器方面的问题。二:服务器3306端口未打开首先需要在安…

    2022年4月11日
    109
  • CAD图纸转换成白色背景SVG格式如何设置其页面大小?

    CAD图纸转换成白色背景SVG格式如何设置其页面大小?

    2021年7月6日
    113

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号