本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:
Mybatis-Plus中逻辑删除与唯一索引冲突的解决方案
一般情况下,对于数据表中不能重复的业务数据字段(比如身份证号,公司名称等等),我们都会为其加上唯一索引。虽然可以在业务代码中进行逻辑校验来规避重复数据被加入到数据库,但是还是建议加上唯一索引,原因如下:
-
我们不能保证所有后端开发者都能进行严密的校验,很可能会有疏漏导致重复数据入库
-
一般校验是否重复的方式为先查询,能查到就是重复,没查到就不重复,此时可添加。但是在高并发场景中,很可能由于并发请求过多,查询时没有重复,而插入之前被别的并发请求插入了跟你想插入的是相同的数据,导致重复数据入库。所以唯一索引可以彻底规避重复数据,是数据库中的最后一道防线
但是一旦引入逻辑删除字段后,唯一索引的功能将与其冲突。假设身份证号是唯一索引,那么删除了某个身份证号的记录,可以再次添加该身份证号的数据,而由于是逻辑删除只是将删除标记更新,并未真正删除,所以此时插入该身份证号的数据仍然会被唯一索引认为是重复数据,插入失败
我们可以按照如下步骤解决逻辑删除和唯一索引冲突的问题:
-
将逻辑未删除值设置为
0
,逻辑删除值设置为
null
-
添加唯一索引时,除了业务相关字段,把逻辑删除字段也包含在唯一索引中
还是假设身份证号唯一索引的例子,这么做以后,身份证号和逻辑删除字段就成了联合唯一索引。当数据未删除时,逻辑删除字段固定为
0
,身份证号是否重复就决定了唯一索引的校验;当数据删除时,逻辑删除字段固定为
null
,由于
null不会和其他字段有组合唯一键的效果
,所以也就相当于解除了唯一键的约束,可以插入身份证号相同的数据
在MyBatis-Plus中,相关配置如下:
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-not-delete-value: 0
logic-delete-value: "null"
注意:logic-delete-value
的配置null一定要加引号,否则删除时会变成set 逻辑删除字段 =
,等号后面没有携带值,导致SQL语法错误。加上引号以后删除的语句才会是正确的set 逻辑删除字段 = null
本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:Mybatis-Plus中逻辑删除与唯一索引冲突的解决方案一般情况下,对于数据表中不能重复的业务数据字段(比如身份证号,公司名称等等),我们都会为其加上唯一索引。虽然可以在业务代码中进行逻辑校验来规避重复数据被加入到数据库,但是还是建议加上唯一索引,原因如下:我们不能保证所有后端开发者都能进行严密的校验,很可能会有疏漏导致重复数据入库一般校验是否重复的方式为先查询,能查到就是重复,没查到就不重复,此时可添加。但是在高并发场景中,很可能由于并发请
表中有逻辑删除字段"deleted",tinyint类型,0表示未删除,其余的表示已删除,近期准备加唯一索引的时候发现问题,假如有某个唯一索引的字段,删除后,又重新创建同样一条记录,再次删除的时候,就会出现唯一索引重复的问题,这个时候,唯一索引和逻辑删除就有冲突了,无法并存。
解决方案:
1.不使用唯一索引
有时候程序校验不严格的时候,会出现各种异常,不能保证所有团队成员每时每刻的意识素质都一定过硬,极不推荐使用
2.去掉逻辑删除字段
基于业务的特殊性,确实是需要软删除,所以直接pass
处理使用 MyBatis-Plus 框架时的,既要使用逻辑删除功能,又要兼容数据库建立唯一索引的问题。
有些啰嗦,想找解决方案直接拉到最后。想了解细节可详细阅读。由于数据安全等原因,通常公司都会收回线上环境的 DELETE 权限不允许物理删除数据,所以通常使用逻辑删除,也就是增加一个逻辑删除的字段,用于标识数据已经删除了。日常业务中,经常遇到不能重复存在是业务数据(比如:电子发票数据,公司信息数据)。我们为了保证数据的唯一性,就需要给其建立唯一索引。
虽然唯一索引好用,但是结合逻辑删除使用就遇到问题了。假设
org.springframework.dao.DuplicateKeyException:
### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: 违反唯一约束条件
(HISTEST.idx_treatment_card_no)找到那个字段违反约束条