解析MyBatisPlus解決邏輯刪除與唯一索引的兼容問(wèn)題
需求背景
比如有張用戶表,在插入或者更新數(shù)據(jù)的時(shí)候,我們需要 用戶名稱
(username),不能重復(fù)。
我們首先考慮的是給該字段創(chuàng)建唯一索引
create unique index uni_username on user(username)
似乎這樣就可以了,然而事情并沒(méi)有那么簡(jiǎn)單。
因?yàn)槲覀儽碇械臄?shù)據(jù)在刪除的時(shí)候不會(huì)真的的刪除,而是采用邏輯刪除,會(huì)有一個(gè) deleted
字段使用0,1標(biāo)識(shí)未刪除與已刪除。
當(dāng)然我們可以考慮將 username
+ deleted
組合成一個(gè)聯(lián)合唯一索引。
create unique index uni_username_deleted on user(username,deleted)
這樣就ok了嗎?
其實(shí)會(huì)有一個(gè)新的問(wèn)題,就是如果同一個(gè)用戶名如果被刪除一次。
再去刪除會(huì)發(fā)現(xiàn)系統(tǒng)報(bào)錯(cuò)了,因?yàn)樵摋l數(shù)據(jù)已經(jīng)存在了,不能在刪除了。
是不是很多時(shí)候因?yàn)檫壿媱h除與唯一索引的沖突,你就不創(chuàng)建唯一索引,想著自己寫(xiě)的代碼自己有信心不會(huì)出現(xiàn)臟數(shù)據(jù)的。
這么想你就太天真啦,數(shù)據(jù)庫(kù)是我們最后一道防線,這道防線都不要了嘛?
阿里巴巴手冊(cè)有關(guān)索引規(guī)范,第一條就是
【強(qiáng)制】業(yè)務(wù)上具有唯一特性的字段,即使是組合字段,也必須建成唯一索引。
手冊(cè)還有這么一句話:
即使在應(yīng)用層做了非常完善的校驗(yàn)和控制,只要沒(méi)有唯一索引,根據(jù)墨菲定律,必然有臟數(shù)據(jù)產(chǎn)生。
所以唯一索引非常有必要?。?!
那該怎么做能讓邏輯刪除與唯一索引兼容?
現(xiàn)在大家比較通用的辦法就是
我們依舊可以將 username + deleted 組合成一個(gè)聯(lián)合唯一索引,但是刪除的時(shí)候deleted不再是固定的1,而是當(dāng)前的主鍵ID,也就是deleted不等于0都是刪除狀態(tài),如果刪除了那deleted值=id值
既然確立了解決方案,那就該思考怎么做?
二、MyBatisPlus邏輯刪除
MyBatisPlus是支持邏輯刪除的,如果確定在哪個(gè)字段是邏輯刪除字段,那就在該字段上添加一個(gè)注解
/** * 1、刪除 0、未刪除 */ @TableLogic(value = "0", delval = "1") private Integer deleted;
這個(gè)一來(lái)操作數(shù)據(jù)是會(huì)自動(dòng)變成如下:
查詢時(shí)
: 查詢條件會(huì)自動(dòng)加上 'AND deleted = 0'刪除時(shí)
: 自定添加 'UPDATE SET deleted = 1 … WHERE … AND deleted = 0'
如果你想刪除的時(shí)候不再是固定1而是id值,那么就可以這樣改
@TableLogic(value = "0", delval = "id") private Integer deleted;
如果想改成全局的那么在配置文件中添加
mybatis-plus: global-config: db-config: logic-delete-value: 1 # 邏輯已刪除值(默認(rèn)為 1) logic-not-delete-value: 0 # 邏輯未刪除值(默認(rèn)為 0)
三、測(cè)試
1、用戶表
CREATE TABLE `user` ( `id` int unsigned AUTO_INCREMENT COMMENT '主鍵', `username` varchar(128) COMMENT '用戶名', `phone` varchar(32) COMMENT '手機(jī)號(hào)', `sex` char(1) COMMENT '性別', `create_time` datetime COMMENT '創(chuàng)建時(shí)間', `update_time` datetime COMMENT '更新時(shí)間', `deleted` tinyint DEFAULT '0' COMMENT '1、刪除 0、未刪除', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1
2、創(chuàng)建對(duì)應(yīng)實(shí)體
@Data @Accessors(chain = true) @TableName("user") public class UserDO implements Serializable { private static final long serialVersionUID = 1L; @TableId(type = IdType.AUTO) private Integer id; /** * 用戶名 */ private String username; /** * 手機(jī)號(hào) */ private String phone; /** * 性別 */ private String sex; /** * 創(chuàng)建時(shí)間 */ private LocalDateTime createTime; /** * 更新時(shí)間 */ private LocalDateTime updateTime; /** * 1、刪除 0、未刪除 */ private Integer deleted; }
3、物理刪除測(cè)試
注意
: 目前 deleted 字段是沒(méi)有添加 @TableLogic注解,同是在全局也沒(méi)有定義邏輯刪除
我們來(lái)看下刪除示例
@Test public void deleteById() { //方式一:根據(jù)id刪除 mapper.deleteById(10); //方式二:根據(jù)指定字段刪除 LambdaQueryWrapper<UserDO> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(UserDO::getSex, "男"); mapper.delete(wrapper); //方式三:手動(dòng)邏輯刪除 UserDO userDO = new UserDO(); userDO.setId(10); userDO.setDeleted(1); mapper.updateById(userDO); }
執(zhí)行結(jié)果
--方式1
DELETE FROM user WHERE id=10
--方式2
DELETE FROM user WHERE (sex = '男')
--方式3
UPDATE user SET deleted=1 WHERE id=10
我們通過(guò)結(jié)果可以看出,如果不添加邏輯刪除標(biāo)識(shí) 那刪除就是物理刪除。
4、邏輯刪除測(cè)試
我們?cè)赿eleted屬性字段 添加 邏輯刪除標(biāo)識(shí)
@TableLogic(value = "0", delval = "id") private Integer deleted;
我們?cè)賮?lái)執(zhí)行上面三個(gè)刪除,看下執(zhí)行結(jié)果
--方式1 UPDATE user SET deleted=id WHERE id=10 AND deleted=0 --方式2 UPDATE user SET deleted=id WHERE deleted=0 AND (sex = '男') --方式3 報(bào)錯(cuò)了
從執(zhí)行結(jié)果來(lái)看,方式一和方式二都從之前的物理刪除變成了邏輯刪除。
但為什么方式三會(huì)報(bào)錯(cuò)呢?我們來(lái)看下報(bào)錯(cuò)的結(jié)果
發(fā)現(xiàn)問(wèn)題了,最終執(zhí)行的SQL竟然是:
UPDATE user WHERE id=? AND deleted=0
為什么是這樣,正常不應(yīng)該是
UPDATE user SET deleted=1 WHERE id=? AND deleted=0
這個(gè)就需要去看Mybatisplus到底做了什么操作,改變了我們的SQL
真相大白了
Mybatisplus在updateById更新時(shí),如果已經(jīng)加了邏輯刪除標(biāo)記,那做SQL拼接的時(shí)候,會(huì)自動(dòng)過(guò)濾掉邏輯刪除的Set拼接
所以在實(shí)際開(kāi)發(fā)中就非常注意,如果你的項(xiàng)目一開(kāi)始是沒(méi)有加Mybatisplus邏輯刪除標(biāo)識(shí)的,后面你在加邏輯刪除標(biāo)識(shí)時(shí),不是說(shuō)加了就好了。
你還需要考慮對(duì)整體項(xiàng)目有沒(méi)有影響,如果之前是用updateById做邏輯刪除,那就會(huì)導(dǎo)致之前的刪除失敗甚至是報(bào)錯(cuò),這一點(diǎn)一定要注意。
到此這篇關(guān)于MyBatisPlus解決邏輯刪除與唯一索引的兼容問(wèn)題的文章就介紹到這了,更多相關(guān)MyBatisPlus邏輯刪除與唯一索引內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MybatisPlus使用@TableLogic實(shí)現(xiàn)邏輯刪除過(guò)程
- MybatisPlus實(shí)現(xiàn)邏輯刪除的示例代碼
- mybatisplus邏輯刪除基本實(shí)現(xiàn)和坑點(diǎn)解決
- mybatisplus的邏輯刪除問(wèn)題
- mybatisPlus填坑之邏輯刪除的實(shí)現(xiàn)
- 詳解MyBatisPlus邏輯刪除與唯一索引沖突問(wèn)題
- MybatisPlus實(shí)現(xiàn)邏輯刪除功能
- mybatisPlus實(shí)現(xiàn)邏輯刪除,自動(dòng)生成創(chuàng)建時(shí)間和更新時(shí)間方式
相關(guān)文章
springboot攔截器不攔截靜態(tài)資源,只攔截controller的實(shí)現(xiàn)方法
這篇文章主要介紹了springboot攔截器不攔截靜態(tài)資源,只攔截controller的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Java實(shí)現(xiàn)簡(jiǎn)易的分詞器功能
搜索功能是具備數(shù)據(jù)庫(kù)功能的系統(tǒng)的一大重要特性和功能,生活中常見(jiàn)的搜索功能基本上都具備了分詞搜索功能.然而ES功能固然強(qiáng)大,但對(duì)于學(xué)生或小項(xiàng)目而言整合起來(lái)太費(fèi)人力物力,若是寫(xiě)個(gè)分詞器就會(huì)使項(xiàng)目錦上添花,使其不僅僅是只能單關(guān)鍵詞搜索的系統(tǒng),需要的朋友可以參考下2021-06-06MybatisPlus中如何調(diào)用Oracle存儲(chǔ)過(guò)程
這篇文章主要介紹了MybatisPlus中如何調(diào)用Oracle存儲(chǔ)過(guò)程的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05原因分析IDEA導(dǎo)入Spring-kafka項(xiàng)目Gradle編譯失敗
這篇文章主要為大家介紹分析了IDEA導(dǎo)入Spring-kafka項(xiàng)目Gradle中編譯失敗原因及解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02JavaWeb?Listener?利用Session統(tǒng)計(jì)在線人數(shù)
這篇文章主要為大家介紹了JavaWeb?Listener?利用Session統(tǒng)計(jì)在線人數(shù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09