1 邏輯刪除
1. 1 什么是邏輯刪除 , 以及邏輯刪除和物理刪除的區(qū)別?
邏輯刪除,可以方便地實現(xiàn)對數(shù)據(jù)庫記錄的邏輯刪除而不是物理刪除。邏輯刪除是指通過更改記錄的狀態(tài)或添加標(biāo)記字段來模擬刪除操作,從而保留了刪除前的數(shù)據(jù),便于后續(xù)的數(shù)據(jù)分析和恢復(fù)。
- 物理刪除:真實刪除,將對應(yīng)數(shù)據(jù)從數(shù)據(jù)庫中刪除,之后查詢不到此條被刪除的數(shù)據(jù)
- 邏輯刪除:假刪除,將對應(yīng)數(shù)據(jù)中代表是否被刪除字段的狀態(tài)修改為“被刪除狀態(tài)”,之后在數(shù)據(jù)庫中仍舊能看到此條數(shù)據(jù)記錄。
因此說,邏輯刪除不是真正的刪除語句 , 其實質(zhì)是更新邏輯刪除字段的更新語句!
1.2 邏輯刪除實現(xiàn):
1.2.1 數(shù)據(jù)庫和實體類添加邏輯刪除字段
1.2.1.1 表添加邏輯刪除字段,可以是一個布爾類型、整數(shù)類型或枚舉類型。用來指示是否已經(jīng)邏輯刪除
ALTER TABLE USER ADD deleted INT DEFAULT 0 ; # int 類型 1 邏輯刪除 0 未邏輯刪除
1.2.1.2 實體類添加邏輯刪除屬性,屬性之上增加邏輯刪除注解
實體類中指定邏輯刪除字段的方法
a. 單一指定
@Data
public class User {
// @TableId
private Integer id;
private String username;
private Integer age;
@TableLogic
// 注解之下的屬性就是判斷是否已經(jīng)邏輯刪除的狀態(tài)字段
//當(dāng)刪除數(shù)據(jù)時,語句自動變更為修改該列的值。默認(rèn)0 未刪除 1 已刪除
//查詢數(shù)據(jù)時,默認(rèn)只查詢邏輯刪除字段為0(未刪除)的數(shù)據(jù)
private Integer deleted;
}
b. 全局指定
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局邏輯刪除的實體字段名(since 3.3.0,配置后可以忽略不配置步驟2)
logic-delete-value: 1 # 邏輯已刪除值(默認(rèn)為 1)
logic-not-delete-value: 0 # 邏輯未刪除值(默認(rèn)為 0)
- 演示邏輯刪除操作
//邏輯刪除
@Test
public void testQuick5(){
//邏輯刪除
userMapper.deleteById(5);
}
執(zhí)行效果:
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5871a482] will not be managed by Spring
==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 5(Integer)
<== Updates: 1
- 測試查詢數(shù)據(jù)
@Test
public void testQuick6(){
//正常查詢.默認(rèn)查詢非邏輯刪除數(shù)據(jù)
userMapper.selectList(null);
}
//SELECT id,name,age,email,deleted FROM user WHERE deleted=0
2 樂觀鎖
對數(shù)據(jù)庫的并發(fā)操作可能導(dǎo)致一些問題:
**解決思路: **
- 悲觀鎖:
悲觀鎖的基本思想是,在整個數(shù)據(jù)訪問過程中,將共享資源鎖定,以確保其他線程或進(jìn)程不能同時訪問和修改該資源。悲觀鎖的核心思想是"先保護(hù),再修改"。在悲觀鎖的應(yīng)用中,線程在訪問共享資源之前會獲取到鎖,并在整個操作過程中保持鎖的狀態(tài),阻塞其他線程的訪問。只有當(dāng)前線程完成操作后,才會釋放鎖,讓其他線程繼續(xù)操作資源。這種鎖機(jī)制可以確保資源獨占性和數(shù)據(jù)的一致性,但是在高并發(fā)環(huán)境下,悲觀鎖的效率相對較低。
- 樂觀鎖:
樂觀鎖的基本思想是,認(rèn)為并發(fā)沖突的概率較低,因此不需要提前加鎖,而是在數(shù)據(jù)更新階段進(jìn)行沖突檢測和處理。樂觀鎖的核心思想是"先修改,后校驗"。在樂觀鎖的應(yīng)用中,線程在讀取共享資源時不會加鎖,而是記錄特定的版本信息。當(dāng)線程準(zhǔn)備更新資源時,會先檢查該資源的版本信息是否與之前讀取的版本信息一致,如果一致則執(zhí)行更新操作,否則說明有其他線程修改了該資源,需要進(jìn)行相應(yīng)的沖突處理。樂觀鎖通過避免加鎖操作,提高了系統(tǒng)的并發(fā)性能和吞吐量,但是在并發(fā)沖突較為頻繁的情況下,樂觀鎖會導(dǎo)致較多的沖突處理和重試操作。
理解點: 悲觀鎖和樂觀鎖是兩種解決并發(fā)數(shù)據(jù)問題的思路,不是具體技術(shù)!!!
具體技術(shù)和方案:
- 樂觀鎖實現(xiàn)方案和技術(shù):
- 版本號/時間戳:為數(shù)據(jù)添加一個版本號或時間戳字段,每次更新數(shù)據(jù)時,比較當(dāng)前版本號或時間戳與期望值是否一致,若一致則更新成功,否則表示數(shù)據(jù)已被修改,需要進(jìn)行沖突處理。
- CAS(Compare-and-Swap):使用原子操作比較當(dāng)前值與舊值是否一致,若一致則進(jìn)行更新操作,否則重新嘗試。
- 無鎖數(shù)據(jù)結(jié)構(gòu):采用無鎖數(shù)據(jù)結(jié)構(gòu),如無鎖隊列、無鎖哈希表等,通過使用原子操作實現(xiàn)并發(fā)安全。
- 悲觀鎖實現(xiàn)方案和技術(shù):
- 鎖機(jī)制:使用傳統(tǒng)的鎖機(jī)制,如互斥鎖(Mutex Lock)或讀寫鎖(Read-Write Lock)來保證對共享資源的獨占訪問。
- 數(shù)據(jù)庫鎖:在數(shù)據(jù)庫層面使用行級鎖或表級鎖來控制并發(fā)訪問。
- 信號量(Semaphore):使用信號量來限制對資源的并發(fā)訪問。
介紹版本號樂觀鎖技術(shù)的實現(xiàn)流程:
- 每條數(shù)據(jù)添加一個版本號字段version
- 取出記錄時,獲取當(dāng)前 version
- 更新時,檢查獲取版本號是不是數(shù)據(jù)庫當(dāng)前最新版本號
- 如果是[證明沒有人修改數(shù)據(jù)], 執(zhí)行更新, set 數(shù)據(jù)更新 , version = version+ 1
- 如果 version 不對[證明有人已經(jīng)修改了],我們現(xiàn)在的其他記錄就是失效數(shù)據(jù)!就更新失敗
3.2.2 使用mybatis-plus數(shù)據(jù)使用樂觀鎖
- 添加樂觀鎖攔截器
package com.sunplanter.Main
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//將樂觀鎖攔截器加入大攔截器中,今后每次項目運行都會自動初始化大攔截器
//MP會在每次更新都對比新舊版本號
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
- 實體類的樂觀鎖字段添加@Version注解 , 數(shù)據(jù)庫添加version字段
ALTER TABLE USER ADD VERSION INT DEFAULT 1 ; # int 類型 樂觀鎖字段
- 支持的數(shù)據(jù)類型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 僅支持 `updateById(id)` 與 `update(entity, wrapper)` 方法
@Version
private Integer version;
- 每次更新前先查詢 , 以獲取舊的version,待稍后修改時對比新的version
//演示樂觀鎖生效場景
@Test
public void testQuick7(){
//步驟1: 先查詢,在更新 獲取version數(shù)據(jù)
//同時查詢兩條,但是version唯一,最后更新的失敗
User user = userMapper.selectById(5);
User user1 = userMapper.selectById(5);
user.setAge(20);
user1.setAge(30);
userMapper.updateById(user);
//樂觀鎖生效,失敗!
userMapper.updateById(user1);
}
3.3 防全表更新和刪除實現(xiàn)
針對 update 和 delete 語句 作用: 阻止惡意的全表更新刪除
添加防止全表更新和刪除攔截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
}
測試全部更新或者刪除
@Test
public void testQuick8(){
User user = new User();
user.setName("custom_name");
user.setEmail("xxx@mail.com");
//Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition of table update operation
//全局更新,報錯
userService.saveOrUpdate(user,null);
}
3.4 MyBatisX
3.4.1 MyBatisX生成基礎(chǔ)項目結(jié)構(gòu)
文章來源:http://www.zghlxwxcb.cn/news/detail-807593.html
3.4.1 MyBatisX生成SQL語句
MP能負(fù)責(zé)生成在xxxmapper接口中根據(jù)提示寫下SQL語句 , 而后ALT+回車選擇MPX生成插件,就可以在xxxMapper.xml中生成SQL代碼文章來源地址http://www.zghlxwxcb.cn/news/detail-807593.html
到了這里,關(guān)于04 MyBatisPlus之邏輯刪除+鎖+防全表更新/刪除+代碼生成插件的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!