Mybatis-Plus同时使用逻辑删除和唯一索引的问题及解决办法

1 问题背景

在开发中,我们经常会有逻辑删除和唯一索引同时使用的情况。但当使用mybatis plus时,如果同时使用逻辑删除和唯一索引,会报数据重复Duplicate entry的问题。

举例来说,有表user,建立唯一索引(user_name,is_del)

CREATE TABLE `user` (`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Id',`user_name` varchar(64) DEFAULT NULL COMMENT '用户名',`is_del` bigint(13) DEFAULT '0' COMMENT '逻辑删除标识',PRIMARY KEY (`id`),UNIQUE KEY `unique_user_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4;

如果我们插入一条数据user_name='张三’的数据,然后再删除它,这时数据表中存在一条记录,如下图:

在这里插入图片描述
这时如果再插入一条’张三’,虽然之前的一条记录已经被逻辑删除,但是唯一索引只建在了user_name上,所以这时会报数据重复的错误

2 第一次改进

我们把唯一索引的组合增加is_del字段

UNIQUE KEY `unique_user_name_is_del` (`user_name`,`is_del`)

这下可以再次插入’张三’这条数据,插入后如下图

在这里插入图片描述
但是如果第二次删除’张三’,则还是会报错,因为已经有一条[‘张三’,1]的数据,当程序想把另一条’zhangsan’的is_del字段值为1时,会因为数据重复失败!

3 第二次改进

此时应该如何改进呢,可以在user表中增加一个del_version字段,用来把已经删除的数据加上版本号,然后将这个字段也加入唯一索引中

CREATE TABLE `user` (`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Id',`user_name` varchar(64) DEFAULT NULL COMMENT '用户名',`del_version` bigint(11) DEFAULT '0' COMMENT '版本标识,用于逻辑删除',`is_del` bigint(13) DEFAULT '0' COMMENT '逻辑删除标识',PRIMARY KEY (`id`),UNIQUE KEY `unique_user_name_is_del_del_version` (`user_name`,`is_del`,`del_version`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4;

未删除的数据del_version=0,已删除的数据del_version修改成这条记录的id(自增id全局唯一),这样既可以保证无法多次插入同名的数据,又可以满足数据可以多次删除的情况
例如,我们两次删除同样数据后,再重新插入,这时数据表中的数据如下:

在这里插入图片描述

4 代码解决方案

我们使用mybatis plus提供的工具生成代码,这时所有的service层接口都会继承 IService 这个接口,这个接口有很多默认方法,实现了对数据库的操作。

我们的思路是,新建一个IBaseService接口,继承IService接口。在这个IBaseService接口中,重写所有和删除相关的方法,在其中设置【del_version】=【自增id】。而原来的所有service层接口,不再继承IService,而是继承我们新的IBaseService。

这样就解决了逻辑删除和唯一索引共用的问题,IBaseService具体代码如下:

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.llbqhh.dao.entity.BaseDO;import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;/*** @Author wuKeFan* @Date 2023/11/08* @Description: 逻辑删除前先更新版本号*/
public interface IBaseService<T extends BaseDO> extends IService<T> {/*** 根据 ID 删除** @param id 主键ID*/@Overridedefault boolean removeById(Serializable id) {T objDO = getBaseMapper().selectById(id);return beforeDelete(objDO) && SqlHelper.retBool(getBaseMapper().deleteById(id));}/*** 删除对象前,先修改其版本号* @param objDO* @return*/default boolean beforeDelete(T objDO) {if (Objects.isNull(objDO)) {return false;}// 逻辑删除前先更新版本号objDO.setDelVersion(objDO.getId());return SqlHelper.retBool(getBaseMapper().updateById(objDO));}/*** 根据 columnMap 条件,删除记录** @param columnMap 表字段 map 对象*/@Overridedefault boolean removeByMap(Map<String, Object> columnMap) {throw new RuntimeException("不支持的数据库删除操作");}/*** 根据 entity 条件,删除记录** @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/@Overridedefault boolean remove(Wrapper<T> queryWrapper) {List<T> objDOS = getBaseMapper().selectList(queryWrapper);if (CollectionUtils.isNotEmpty(objDOS)) {objDOS.forEach(objDO -> beforeDelete(objDO));}return SqlHelper.retBool(getBaseMapper().delete(queryWrapper));}/*** 删除(根据ID 批量删除)** @param idList 主键ID列表*/@Overridedefault boolean removeByIds(Collection<? extends Serializable> idList) {if (CollectionUtils.isEmpty(idList)) {return false;}List<T> objDOS = getBaseMapper().selectBatchIds(idList);if (CollectionUtils.isNotEmpty(objDOS)) {objDOS.forEach(objDO -> beforeDelete(objDO));}return SqlHelper.retBool(getBaseMapper().deleteBatchIds(idList));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/185666.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt实现动态桌面小精灵(含源码)

目录 一、设计思路 二、部分源码演示 三、源码地址 🌈write in front🌈 🧸大家好,我是三雷科技.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流. 🆔本文由三雷科技原创 CSDN首发🐒 如需转载还请通知⚠️ 📝个人主页:三雷科技🧸—CSDN博客 🎁欢…

了解高防服务器的工作原理

在当今互联网时代&#xff0c;网络安全问题日益突出&#xff0c;各种网络攻击层出不穷。为了保护企业的网络安全&#xff0c;高防服务器应运而生。那么&#xff0c;你是否了解高防服务器的工作原理呢?下面就让我们一起来探索一下。 高防服务器是一种能够有效抵御各种网络攻击的…

万界星空科技MES系统软件体系架构及应用

MES系统是数字化车间的核心。MES通过数字化生产过程控制&#xff0c;借助自动化和智能化技术手段&#xff0c;实现车间制造控制智能化、生产过程透明化、制造装备数控化和生产信息集成化。生产管理MES系统主要包括车间管理系统、质量管理系统、资源管理系统及数据采集和分析系统…

C语言编写一个程序采集招聘信息

因为在这里无法详细解释每行代码和步骤。但是&#xff0c;我可以给大家一个使用Python和requests库编写的简单爬虫程序的例子&#xff0c;它可以从网站上获取招聘信息。你可以根据这个例子&#xff0c;将其改写为使用C语言编写的爬虫程序。 import requests# 指定爬虫IP信息 pr…

软件测试|测试方法论—边界值

边界值分析法是一种很实用的黑盒测试用例方法&#xff0c;它具有很强的发现故障的能力。边界值分析法也是作为对等价类划分法的补充&#xff0c;测试用例来自等价类的边界。 这个方法其实是在测试实践当中发现&#xff0c;Bug 往往出现在定义域或值域的边界上&#xff0c;而不…

“锡安主义”贝尔福宣言希伯来抵抗运动犹太启蒙改革运动奋锐党闪米特人雅利安人

目录 “锡安主义” 贝尔福宣言 希伯来抵抗运动 犹太启蒙改革运动 奋锐党 闪米特人 雅利安人 “锡安主义” “锡安主义”是一种政治和民族运动&#xff0c;旨在支持并促进犹太人建立自己的国家并在历史上与宗教上的祖先之地——巴勒斯坦地区建立一个独立的国家。这一运动…

nginx图片资源管理转发

目标: 服务器上面 /home/images 里面作为文件资源管理器 代码: server {listen 80;server_name hello.world.cn;#apple-app和接口的关联文件location ~.*(images/miniapp)*\.(gif|jpg|jpeg|png)$ {root /home/;try_files $uri $uri/ 404;add_header Cache-Control &q…

“第六十四天” 字扩展和位扩展,外部存储器

存储器和CPU的连接; 现在的计算机MAR&#xff0c;MDR通常集成在CPU内部。存储芯片内只需一个普通的寄存器&#xff08;暂存输入&#xff0c;输出数据&#xff09;。 位扩展&#xff0c;字扩展&#xff0c;字位同时扩展&#xff1b; 位扩展&#xff1a; 位扩展的增加的是主存的…

unity【动画】脚本_角色动画控制器 c#

首先创建一个代码文件夹Scripts 从人物角色Player的基类开始 创建IPlayer类 首先我们考虑到如果不挂载MonoBehaviour需要将角色设置成预制体实例化到场景上十分麻烦&#xff0c; 所以我们采用继承MonoBehaviour类的角色基类方法写代码 也就是说这个脚本直接绑定在角色物体…

经典OJ题:随机链表的复制

目录 题目&#xff1a; 本题的解图关键在于画图与看图&#xff01; 思路分析&#xff1a; 方法一&#xff1a;暴力求解法。 方法二&#xff1a;插入法 方法解析&#xff1a; 步骤一、插入 步骤二、 处理每一个copy的randdom指针⭐————重点 步骤三、拆卸节点 代码…

软件测试|iOS 自动化测试——技术方案、环境配置

移动端的自动化测试&#xff0c;最常见的是 Android 自动化测试&#xff0c;我个人觉得 Android 的测试优先级会更高&#xff0c;也更开放&#xff0c;更容易测试&#xff1b;而 iOS 相较于 Android 要安全稳定的多&#xff0c;但也是一个必须测试的方向&#xff0c;这个系列文…

OAuth 2.0实现统一认证

OAuth 2.0协议概念&#xff1a; OAuth 是 Open Authorization 的简写。OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 OAuth 的授权不会使第三方触及到用户的帐号信息&#xff08;如用户名与密码&#xff09;&#xff0c;即第…

开源:特殊的垄断

免责声明&#xff1a;本博客旨在分享我对开源策略的理解和体会&#xff0c;不代表任何组织或机构的立场或观点&#xff0c;也不构成任何商业或投资的建议或担保。本博客的内容可能存在错误或遗漏&#xff0c;也可能随着时间的推移而变得过时或不适用。请在使用或依赖本博客的内…

Google play的企业开发者账号比个人号上包成功率更高?

众所周知&#xff0c;Google play作为全球最大的Android应用市场&#xff0c;是开发者们推广应用的首选平台。Google play平台提供了两种账号类型&#xff1a;个人开发者和企业开发者&#xff0c;开发者们可以选择创建个人开发者账号或者企业开发者账号进行应用上架。 不过&am…

Stable Diffusion WebUI扩展sd-webui-controlnet之Canny

什么是Canny? 简单来说,Canny是计算机视觉领域的一种边缘检测算法。 关于Canny算法大家可以去看我下面这篇博客,里面详细介绍了Canny算法的原理以及代码演示。 OpenCV竟然可以这样学!成神之路终将不远(十五)_maxminval opencv-CSDN博客文章浏览阅读111次。14 图像梯度…

论文阅读——Detection Hub(cvpr2023)

Detection Hub: Unifying Object Detection Datasets via Query Adaptation on Language Embedding 一、要解决的问题 大规模数据集可以提高模型性能&#xff0c;但是当训练多类别单一模型时&#xff0c;大规模数据集不能用在目标检测任务上&#xff0c;因为两个困难&#xff1…

latex cite命令、款式

UTS SEDE 的 latex 模板 [1,2] 用 biblatex&#xff0c;默认用的引用格式是 ieee。然而 Research Foundation 的 literature review 这个作业要用 APA 7&#xff0c;想在保留 biblatex 的情况下区分有括号和无括号两种引用格式&#xff0c;即 [3] 中 \citet、\citep 的分别。 …

基于selenium的pyse自动化测试框架

介绍&#xff1a; pyse基于selenium&#xff08;webdriver&#xff09;进行了简单的二次封装&#xff0c;比selenium所提供的方法操作更简洁。 特点&#xff1a; 默认使用CSS定位&#xff0c;同时支持多种定位方法&#xff08;id\name\class\link_text\xpath\css&#xff09…

Next.js 项目——从入门到入门(Eslint+Prettier)

Next.js官方文档地址 什么是 Next.js 这是一个用于生产环境的 React 框架。 Next.js 为您提供生产环境所需的所有功能以及最佳的开发体验&#xff1a;包括静态及服务器端融合渲染、 支持 TypeScript、智能化打包、 路由预取等功能&#xff0c;无需任何配置。 功能&#xff…

mac 安装 selenium + chrome driver

前言 使用 selenium 模拟浏览器渲染数据&#xff0c;需要依赖各浏览器的驱动才能完成&#xff0c;因此需要单独安装chrome driver 查看本地 chrome 浏览器的版本 可以看到我这里已经是 arm 架构下最新的版本了 下载对应的 chrome driver 访问下面的地址&#xff1a; Chrome…