您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么用MyBatisPlus解決邏輯刪除與唯一索引的兼容問題”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“怎么用MyBatisPlus解決邏輯刪除與唯一索引的兼容問題”文章能幫助大家解決問題。
比如有張用戶表,在插入或者更新數據的時候,我們需要 用戶名稱
(username),不能重復。
我們首先考慮的是給該字段創建唯一索引
create unique index uni_username on user(username)
似乎這樣就可以了,然而事情并沒有那么簡單。
因為我們表中的數據在刪除的時候不會真的的刪除,而是采用邏輯刪除,會有一個 deleted
字段使用0,1標識未刪除與已刪除。
當然我們可以考慮將 username
+ deleted
組合成一個聯合唯一索引。
create unique index uni_username_deleted on user(username,deleted)
這樣就ok了嗎?
其實會有一個新的問題,就是如果同一個用戶名如果被刪除一次。
再去刪除會發現系統報錯了,因為該條數據已經存在了,不能在刪除了。
是不是很多時候因為邏輯刪除與唯一索引的沖突,你就不創建唯一索引,想著自己寫的代碼自己有信心不會出現臟數據的。
這么想你就太天真啦,數據庫是我們最后一道防線,這道防線都不要了嘛?
阿里巴巴手冊有關索引規范,第一條就是
【強制】業務上具有唯一特性的字段,即使是組合字段,也必須建成唯一索引。
手冊還有這么一句話:
即使在應用層做了非常完善的校驗和控制,只要沒有唯一索引,根據墨菲定律,必然有臟數據產生。
所以唯一索引非常有必要!!!
那該怎么做能讓邏輯刪除與唯一索引兼容?
現在大家比較通用的辦法就是
我們依舊可以將 username + deleted 組合成一個聯合唯一索引,但是刪除的時候deleted不再是固定的1,而是當前的主鍵ID,也就是deleted不等于0都是刪除狀態,如果刪除了那deleted值=id值
既然確立了解決方案,那就該思考怎么做?
MyBatisPlus是支持邏輯刪除的,如果確定在哪個字段是邏輯刪除字段,那就在該字段上添加一個注解
/** * 1、刪除 0、未刪除 */ @TableLogic(value = "0", delval = "1") private Integer deleted;
這個一來操作數據是會自動變成如下:
查詢時
: 查詢條件會自動加上 'AND deleted = 0'
刪除時
: 自定添加 'UPDATE SET deleted = 1 … WHERE … AND deleted = 0'
如果你想刪除的時候不再是固定1而是id值,那么就可以這樣改
@TableLogic(value = "0", delval = "id") private Integer deleted;
如果想改成全局的那么在配置文件中添加
mybatis-plus: global-config: db-config: logic-delete-value: 1 # 邏輯已刪除值(默認為 1) logic-not-delete-value: 0 # 邏輯未刪除值(默認為 0)
CREATE TABLE `user` ( `id` int unsigned AUTO_INCREMENT COMMENT '主鍵', `username` varchar(128) COMMENT '用戶名', `phone` varchar(32) COMMENT '手機號', `sex` char(1) COMMENT '性別', `create_time` datetime COMMENT '創建時間', `update_time` datetime COMMENT '更新時間', `deleted` tinyint DEFAULT '0' COMMENT '1、刪除 0、未刪除', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1
@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; /** * 手機號 */ private String phone; /** * 性別 */ private String sex; /** * 創建時間 */ private LocalDateTime createTime; /** * 更新時間 */ private LocalDateTime updateTime; /** * 1、刪除 0、未刪除 */ private Integer deleted; }
注意
: 目前 deleted 字段是沒有添加 @TableLogic注解,同是在全局也沒有定義邏輯刪除
我們來看下刪除示例
@Test public void deleteById() { //方式一:根據id刪除 mapper.deleteById(10); //方式二:根據指定字段刪除 LambdaQueryWrapper<UserDO> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(UserDO::getSex, "男"); mapper.delete(wrapper); //方式三:手動邏輯刪除 UserDO userDO = new UserDO(); userDO.setId(10); userDO.setDeleted(1); mapper.updateById(userDO); }
執行結果
--方式1
DELETE FROM user WHERE id=10
--方式2
DELETE FROM user WHERE (sex = '男')
--方式3
UPDATE user SET deleted=1 WHERE id=10
我們通過結果可以看出,如果不添加邏輯刪除標識 那刪除就是物理刪除。
我們在deleted屬性字段 添加 邏輯刪除標識
@TableLogic(value = "0", delval = "id") private Integer deleted;
我們再來執行上面三個刪除,看下執行結果
--方式1 UPDATE user SET deleted=id WHERE id=10 AND deleted=0 --方式2 UPDATE user SET deleted=id WHERE deleted=0 AND (sex = '男') --方式3 報錯了
從執行結果來看,方式一和方式二都從之前的物理刪除變成了邏輯刪除。
但為什么方式三會報錯呢?我們來看下報錯的結果
發現問題了,最終執行的SQL竟然是:
UPDATE user WHERE id=? AND deleted=0
為什么是這樣,正常不應該是
UPDATE user SET deleted=1 WHERE id=? AND deleted=0
這個就需要去看Mybatisplus到底做了什么操作,改變了我們的SQL
真相大白了
Mybatisplus在updateById更新時,如果已經加了邏輯刪除標記,那做SQL拼接的時候,會自動過濾掉邏輯刪除的Set拼接
所以在實際開發中就非常注意,如果你的項目一開始是沒有加Mybatisplus邏輯刪除標識的,后面你在加邏輯刪除標識時,不是說加了就好了。
你還需要考慮對整體項目有沒有影響,如果之前是用updateById做邏輯刪除,那就會導致之前的刪除失敗甚至是報錯,這一點一定要注意。
關于“怎么用MyBatisPlus解決邏輯刪除與唯一索引的兼容問題”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。