MyBatis-Flex 邏輯刪除的用法小結(jié)
一、@Column
MyBatis-Flex 提供了 @Column 用來對字段進行更多的配置,以下是 @Column 的代碼定義:
public @interface Column {
/**
* 字段名稱
*/
String value() default "";
/**
* 是否忽略該字段,可能只是業(yè)務(wù)字段,而非數(shù)據(jù)庫對應(yīng)字段
*/
boolean ignore() default false;
/**
* insert 的時候默認值,這個值會直接被拼接到 sql 而不通過參數(shù)設(shè)置
*/
String onInsertValue() default "";
/**
* update 的時候自動賦值,這個值會直接被拼接到 sql 而不通過參數(shù)設(shè)置
*/
String onUpdateValue() default "";
/**
* 是否是大字段,大字段 APT 不會生成到 DEFAULT_COLUMNS 里
*/
boolean isLarge() default false;
/**
* 是否是邏輯刪除字段,一張表中只能存在 1 一個邏輯刪除字段
* 邏輯刪除的字段,被刪除時,會設(shè)置為 1,正常狀態(tài)為 0
*/
boolean isLogicDelete() default false;
/**
* 是否為樂觀鎖字段,若是樂觀鎖字段的話,數(shù)據(jù)更新的時候會去檢測當(dāng)前版本號,若更新成功的話會設(shè)置當(dāng)前版本號 +1
* 只能用于數(shù)值的字段
*/
boolean version() default false;
/**
* 配置的 jdbcType
*/
JdbcType jdbcType() default JdbcType.UNDEFINED;
/**
* 自定義 TypeHandler
*/
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
}二、邏輯刪除相關(guān)場景
通過@Column設(shè)置字段邏輯刪除
邏輯刪除指的是在刪除數(shù)據(jù)的時候,并非真正的去刪除,而是將表中列所對應(yīng)的狀態(tài)字段(status)做修改操作, 實際上并未刪除目標(biāo)數(shù)據(jù)。
我們可以進行表的字段設(shè)計時,用一個列標(biāo)識該數(shù)據(jù)的 "刪除狀態(tài)",在 mybatis-flex 中,正常狀態(tài)的值為 0, 已刪除 的值為 1(可以通過設(shè)置 FlexGlobalConfig 來修改這個值)。
@Column(isLogicDelete = true) private int isDeleted; /* 對應(yīng)數(shù)據(jù)庫的表結(jié)構(gòu)中為: is_deleted tinyint(1) default 0 numm comment '是否已邏輯刪除 0-否 1-是'; */
當(dāng) "tb_account" 的數(shù)據(jù)被刪除時( is_delete = 1 時),我們通過 MyBatis-Flex 的 selectOneById 去查找數(shù)據(jù)時,會查詢不到數(shù)據(jù)。 原因是 selectOneById 會自動添加上 is_delete = 0 條件,執(zhí)行的 sql 如下:
SELECT * FROM tb_account where id = ? and is_delete = 0
不僅僅是 selectOneById 方法會添加 is_delete = 0 條件,BaseMapper 的以下方法也都會添加該條件:
- selectOneBy**
- selectListBy**
- selectCountBy**
- paginate
同時,比如 Left Join 或者子查詢等,若 子表也設(shè)置了邏輯刪除字段, 那么子表也會添加相應(yīng)的邏輯刪除條件,例如:
QueryWrapper query1 = QueryWrapper.create()
.select()
.from(ACCOUNT)
.leftJoin(ARTICLE).as("a").on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
.where(ACCOUNT.AGE.ge(10));
/*
其執(zhí)行的 SQL 如下:
SELECT *
FROM `tb_account`
LEFT JOIN `tb_article` AS `a`
ON `a`.`is_delete` = 0 and `tb_account`.`id` = `a`.`account_id`
WHERE `tb_account`.`age` >= 10
AND `tb_account`.`is_delete` = 0
*/在 left join on 條件自動添加a.is_delete = 0,并在 where 條件添加上 tb_account.is_delete = 0。
在邏輯刪除的基礎(chǔ)上,自動更新更新時間update_time
(1)數(shù)據(jù)填充指的是,當(dāng) Entity 數(shù)據(jù)被插入或者更新的時候,會為字段進行一些默認的數(shù)據(jù)設(shè)置。這個非常有用,比如當(dāng)某個 entity 被插入時候 會設(shè)置一些數(shù)據(jù)插入的時間、數(shù)據(jù)插入的用戶 id,多租戶的場景下設(shè)置當(dāng)前租戶信息等等。
MyBatis-Flex 提供了兩種方式,幫助開發(fā)者進行數(shù)據(jù)填充。
- 通過 @Table 注解的 onInsert 和 onUpdate配置進行操作。
- 通過 @Column 注解的 onInsertValue 和 onUpdateValue配置進行操作。
@Table的注解和@Column注解的填充有什么區(qū)別?
- @Table 注解的 onInsert 主要是在 Java 應(yīng)用層面進行數(shù)據(jù)設(shè)置。
- @Column 注解的 onInsertValue 則是在數(shù)據(jù)庫層面進行數(shù)據(jù)設(shè)置。
首先,需要在后端項目的model實體類中,通過注解配置將該類的對象屬性createTime和updateTime,映射到數(shù)據(jù)庫表中的特定字段create_time和update_time的默認值設(shè)置等信息。
@Column(onInsertValue = "now()") private Date createTime; @Column(onUpdateValue = "now()", onInsertValue = "now()") private Date updateTime; @Column(isLogicDelete = true) private int isDeleted; /* 對應(yīng)數(shù)據(jù)庫的表結(jié)構(gòu)中為: create_time timestamp null comment '創(chuàng)建時間'; update_time timestamp null comment '更新時間'; is_deleted tinyint(1) default 0 numm comment '是否已邏輯刪除 0-否 1-是'; */
其中,onInsertValue表示當(dāng)數(shù)據(jù)被更新時,設(shè)置的默認值。onInsertValue配置的內(nèi)容 "now()" 會直接參與 SQL 的賦值拼接。而onUpdateValue表示當(dāng)數(shù)據(jù)被更新時,設(shè)置的默認值。onUpdateValue配置的內(nèi)容 "now()" 會直接參與 SQL 的賦值拼接。
在 insert 中,onInsertValue 配置的內(nèi)容會直接參與 SQL 拼接,而不是通過 JDBC 的 Statement 參數(shù)設(shè)置,需要開發(fā)者注意 onInsertValue 的內(nèi)容,否則可能會造成 SQL 錯誤。
(2)UpdateChain 是一個對 UpdateEntity、UpdateWrapper 等進行封裝的一個工具類,方便用戶用于進行鏈式操作。
假設(shè)我們要更新 Account 的 userName 為 "張三",更新年齡在之前的基礎(chǔ)上加 1,更新代碼如下:
@Test
public void testUpdateChain() {
UpdateChain.of(Account.class)
.set(Account::getUserName, "張三")
.setRaw(Account::getAge, "age + 1")
.where(Account::getId).eq(1)
.update();
}
/*
以上方法調(diào)用時,MyBatis-Flex 內(nèi)部執(zhí)行的 SQL 如下:
sql
UPDATE `tb_account` SET `user_name` = '張三' , `age` = age + 1
WHERE `id` = 1
*/經(jīng)過測試之后,發(fā)現(xiàn)dataMapper.deleteBatchById(idsList)似乎不會自動更新時間update_time,不知道為什么。不是說當(dāng)調(diào)用 deleteBatchById()方法時,MyBatis-Flex 會根據(jù)實體類信息和注解配置,動態(tài)生成一條更新語句,而不是刪除語句嗎??按道理來說,更新語句不應(yīng)該會觸發(fā)更新時間update_time字段的自動更新嗎?(沒搞明白。。)
因此,可以通過MyBatis-Flex 提供的鏈式操作方式,來替換掉基礎(chǔ)的deletedById()方法。
// dataMapper.deleteBatchByIds(idsList); UpdateChain.of(dataMapper) .set(DataModel::getIsDeleted, 1) .where(DataModel::getIsDeleted, 0) .and(DataModel::getId).in(idsList) .update();
這樣MyBatis-Flex框架就會走更新語句的流程,數(shù)據(jù)庫表中就可以完成自動更新update_time更新時間字段了。
跳過邏輯刪除處理
在某些場景下,比如說需要構(gòu)建回收站功能,那我們在執(zhí)行查詢、更新或刪除數(shù)據(jù)時,有必要跳過 MyBatis-Flex 自動添加的邏輯刪除的相關(guān)條件。
此時,我們可以使用 LogicDeleteManager.execWithoutLogicDelete() 方法處理。這種方法在需要對所有數(shù)據(jù)進行操作時非常有用,比如批量導(dǎo)出數(shù)據(jù)、進行數(shù)據(jù)恢復(fù)等場景。
LogicDeleteManager 是一個用于處理邏輯刪除的管理器。execWithoutLogicDelete() 方法的作用是在執(zhí)行某些操作時忽略邏輯刪除的規(guī)則。這意味著,當(dāng)使用這個方法執(zhí)行查詢、插入、更新或刪除操作時,系統(tǒng)不會考慮邏輯刪除標(biāo)志,即會處理所有數(shù)據(jù),包括那些被標(biāo)記為已刪除的數(shù)據(jù)。
比如,
LogicDeleteManager.execWithoutLogicDelete(()->
accountMapper.deleteById(1)
);以上代碼中,accountMapper 會直接對 Account 數(shù)據(jù)進行物理刪除,忽略邏輯刪除字段配置。
代碼如下:
LogicDeleteManager.execWithoutLogicDelete(()->{
// 此處寫邏輯
UpdateChain.of(dataMapper)
.set(DataModel::getIsDeleted, 0)
.where(DataModel::getIsDeleted, 1)
.and(DataModel::getId).in(idsList)
.update();
});上述代碼中,UpdateChain.of(dataMapper) 創(chuàng)建了一個數(shù)據(jù)映射器對象dataMapper的更新鏈對象。.set(DataModel::getIsDeleted, 0) 設(shè)置 DataModel 的 isDeleted 字段值為 0,表示未刪除狀態(tài)。.where(DataModel::getIsDeleted, 1) 指定更新條件之一是isDeleted 字段值為 1,即邏輯上已被刪除的數(shù)據(jù)。.and(DataModel::getId).in(idsList) 添加額外的條件:id 字段的值必須在 idsList 列表中。.update() 執(zhí)行更新操作。
這段代碼的目的是在邏輯刪除被忽略的情況下,將指定 id 的數(shù)據(jù)從邏輯刪除狀態(tài)恢復(fù)到未刪除狀態(tài)。具體來說,只有那些 isDeleted 字段值為 1 并且 id 在 idsList 中的數(shù)據(jù)才會被更新。更新后,這些數(shù)據(jù)的 isDeleted 字段值會被設(shè)置為 0,表示這些數(shù)據(jù)不再被視為已刪除。
到此這篇關(guān)于MyBatis-Flex 邏輯刪除的用法小結(jié)的文章就介紹到這了,更多相關(guān)MyBatis-Flex 邏輯刪除內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatis-Flex實現(xiàn)分頁查詢的示例代碼
- Mybatis-flex整合達夢數(shù)據(jù)庫的實現(xiàn)示例
- Spring Boot整合MyBatis-Flex全過程
- SpringBoot使用MyBatis-Flex實現(xiàn)靈活的數(shù)據(jù)庫訪問
- mybatis-flex實現(xiàn)鏈式操作的示例代碼
- mybatis-flex實現(xiàn)多數(shù)據(jù)源操作
- MyBatis-Flex實現(xiàn)多表聯(lián)查(自動映射)
- Springboot集成Mybatis-Flex的示例詳解
- mybatis-flex與springBoot整合的實現(xiàn)示例
相關(guān)文章
Java 調(diào)用Restful API接口的幾種方式(HTTPS)
這篇文章主要介紹了Java 調(diào)用Restful API接口的幾種方式(HTTPS),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02
Spring探秘之如何妙用BeanPostProcessor
BeanPostProcessor也稱為Bean后置處理器,它是Spring中定義的接口,在Spring容器的創(chuàng)建過程中會回調(diào)BeanPostProcessor中定義的兩個方法,這篇文章主要給大家介紹了關(guān)于Spring探秘之如何妙用BeanPostProcessor的相關(guān)資料,需要的朋友可以參考下2022-01-01
Spring?Cloud微服務(wù)架構(gòu)Sentinel數(shù)據(jù)雙向同步
這篇文章主要為大家介紹了Spring?Cloud微服務(wù)架構(gòu)Sentinel數(shù)據(jù)雙向同步示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10

