📢📢📢📣📣📣
哈嘍!大家好,我是【一心同學】,一位上進心十足的【Java領域博主】!😜😜😜
?【一心同學】的寫作風格:喜歡用【通俗易懂】的文筆去講解每一個知識點,而不喜歡用【高大上】的官方陳述,
?【一心同學】博客的領域是【面向后端技術】的學習,未來會持續更新更多的【后端技術】以及【學習心得】,
?如果有對【后端技術】感興趣的【小可愛】,歡迎關注【一心同學】💞💞💞
??????感謝各位大可愛小可愛!??????
目錄
前言
一、@TableName
1.1 介紹
1.2 使用
二、@TableId
2.1 介紹
2.2 AUTO屬性
2.3 INPUT屬性
2.4 AUTO與INPUT對比
三、@TableField
3.1 介紹
3.2 普通屬性
3.3 自動填充屬性
四、樂觀鎖
4.1 介紹
4.2 注意事項
4.3 實作樂觀鎖
4.4 測驗
五、邏輯洗掉
5.1 介紹
5.2 實作邏輯洗掉
5.3 測驗
小結
前言
本篇博客將詳細介紹MyBatis-Plus中的常用注解以及其注意事項,并會對其常用的屬性進行舉例說明,而不常用的屬性大家可根據描述資訊進行了解,
一、@TableName
1.1 介紹
- 描述:表名注解,映射資料庫的表名
- 使用位置:物體類
| 屬性 | 型別 | 必須指定 | 默認值 | 描述 |
|---|---|---|---|---|
| value | String | 否 | "" | 表名 |
| schema | String | 否 | "" | schema |
| keepGlobalPrefix | boolean | 否 | false | 是否保持使用全域的 tablePrefix 的值(當全域 tablePrefix 生效時) |
| resultMap | String | 否 | "" | xml 中 resultMap 的 id(用于滿足特定型別的物體類物件系結) |
| autoResultMap | boolean | 否 | false | 是否自動構建 resultMap 并使用(如果設定 resultMap 則不會進行 resultMap 的自動構建與注入) |
| excludeProperty | String[] | 否 | {} | 需要排除的屬性名 @since 3.3.1 |
1.2 使用
使用場景:當我們的物體類名跟我們的資料庫表名不一致時,可根據@TableName來指定資料庫表名,
例如:
我們的資料庫表名是叫做person,但我們的Java物體類中卻叫做User,
?
?
解決映射沖突:
添加注解@TableName(value = "person")
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "person")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
二、@TableId
2.1 介紹
- 描述:主鍵注解
- 使用位置:物體類主鍵欄位
| 屬性 | 型別 | 必須指定 | 默認值 | 描述 |
|---|---|---|---|---|
| value | String | 否 | "" | 主鍵欄位名 |
| type | Enum | 否 | IdType.NONE | 指定主鍵型別 |
| 值 | 描述 |
|---|---|
| AUTO | 資料庫自增 |
| NONE | 無狀態,該型別為未設定主鍵型別(注解里等于跟隨全域,全域里約等于 INPUT)雪花演算法實作 |
| INPUT | 需要開發者手動賦值 |
| ASSIGN_ID | MP 分配 ID,Long、Integer、String |
| ASSIGN_UUID | 分配 UUID,Strinig |
我們講解在IdType中兩個最常見的屬性:AUTO和INPUT
2.2 AUTO屬性
- 使用前提:需要在資料庫中將主鍵設定為自增,
- 生成ID演算法:【雪花演算法】,基本可以保證全球唯一ID值,
- 特點:生成的ID值在原來的ID基礎上自增,并且會將ID值回填到我們的Java物件中,
注意:對主鍵使用了AUTO,那么我們自行注入的ID值將會被自動生成的ID覆寫,
代碼演示:
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
測驗:
我們在插入時自定義ID值,
@Test
void test4() {
// 我們沒有自定義id,它會幫我們自動生成id
Person person =new Person();
person.setId(2L);
person.setName("一心同學");
person.setAge(18);
person.setEmail("123456@qq.com");
int result=personMapper.insert(person);
System.out.println(result);// 受影響的行數
System.out.println(person);//可以發現,id會自動回填
}
結果:
發現1:可以發現MP并沒有采納我們的ID值,因為其注入陳述句中根本就沒有我們的主鍵id,而是選擇用【雪花演算法】自動生成的ID值,
發現2:自動生成的ID值自動回填到我們的Java物件中了,
?
2.3 INPUT屬性
生成ID演算法:【雪花演算法】,基本可以保證全球唯一ID值,
特點:開發者沒有手動賦值,則資料庫通過自增的方式給主鍵賦值,如果開發者手動賦值,則存入該值,
注意:并不會回填到我們的Java物件中,
代碼演示:
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
@TableId(type = IdType.INPUT)
private Long id;
private String name;
private Integer age;
private String email;
}
(1)自定義ID測驗
@Test
void test4() {
//我們自定義ID,則會使用我們的ID,否則自動生成ID
Person person =new Person();
person.setId(5L);
person.setName("一心同學2");
person.setAge(18);
person.setEmail("123456@qq.com");
int result=personMapper.insert(person);
System.out.println(result);// 受影響的行數
System.out.println(person);
}
結果:可以發現,MP是采用我們自定義的ID值的,
?
(2)不定義ID值測驗
@Test
void test4() {
//我們自定義ID,則會使用我們的ID,否則自動生成ID
Person person =new Person();
person.setName("一心同學3");
person.setAge(18);
person.setEmail("123456@qq.com");
int result=personMapper.insert(person);
System.out.println(result);// 受影響的行數
System.out.println(person);//發現不會回填!
}
結果:可以發現,當我們沒有進行ID的定義時,MP將會通過自增的方式給主鍵賦值,并且不會將賦完的值注入到我們的Java物件,
?
但在我們資料庫中是有Id值的,只是沒回填到Java物件而已,
?
2.4 AUTO與INPUT對比
| Type | 演算法 | 特點 | 是否覆寫自定義值 | 是否回填 |
| AUTO | 雪花演算法 | 生成的ID值在原來的ID基礎上自增 | 是 | 是 |
| INPUT | 雪花演算法 | 開發者沒有手動賦值,則資料庫通過自增的方式給主鍵賦值,如果開發者手動賦值,則存入該值, | 否 | 否 |
三、@TableField
3.1 介紹
描述:欄位注解(非主鍵)
| 屬性 | 型別 | 必須指定 | 默認值 | 描述 |
|---|---|---|---|---|
| value | String | 否 | "" | 資料庫欄位名 |
| exist | boolean | 否 | true | 是否為資料庫表欄位 |
| condition | String | 否 | "" | 欄位 where 物體查詢比較條件,有值設定則按設定的值為準,沒有則為默認全域的 %s=#{%s},參考(opens new window) |
| update | String | 否 | "" | 欄位 update set 部分注入,例如:當在version欄位上注解update="%s+1" 表示更新時會 set version=version+1 (該屬性優先級高于 el 屬性) |
| insertStrategy | Enum | 否 | FieldStrategy.DEFAULT | 舉例:NOT_NULLinsert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>) |
| updateStrategy | Enum | 否 | FieldStrategy.DEFAULT | 舉例:IGNOREDupdate table_a set column=#{columnProperty} |
| whereStrategy | Enum | 否 | FieldStrategy.DEFAULT | 舉例:NOT_EMPTYwhere <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if> |
| fill | Enum | 否 | FieldFill.DEFAULT | 欄位自動填充策略 |
| select | boolean | 否 | true | 是否進行 select 查詢 |
| keepGlobalFormat | boolean | 否 | false | 是否保持使用全域的 format 進行處理 |
| jdbcType | JdbcType | 否 | JdbcType.UNDEFINED | JDBC 型別 (該默認值不代表會按照該值生效) |
| typeHandler | Class<? extends TypeHandler> | 否 | UnknownTypeHandler.class | 型別處理器 (該默認值不代表會按照該值生效) |
| numericScale | String | 否 | "" | 指定小數點后保留的位數 |
| 值 | 描述 |
|---|---|
| IGNORED | 忽略判斷 |
| NOT_NULL | 非 NULL 判斷 |
| NOT_EMPTY | 非空判斷(只對字串型別欄位,其他型別欄位依然為非 NULL 判斷) |
| DEFAULT | 追隨全域配置 |
| 值 | 描述 |
|---|---|
| DEFAULT | 默認不處理 |
| INSERT | 插入時填充欄位 |
| UPDATE | 更新時填充欄位 |
| INSERT_UPDATE | 插入和更新時填充欄位 |
看到上面這么多屬性,是不是突然就懵了,不要怕!【一心同學】在這里,對于上面的屬性,在我們開發中一些是不常用的,【一心同學】在這里用代碼演示幾個常見的屬性,大家務必掌握,
3.2 普通屬性
代碼演示:
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "person")
public class User {
@TableId(type=IdType.AUTO)
private Long id;
// 當該欄位名稱與資料庫名字不一致
@TableField(value = "name")
private String name;
// 不查詢該欄位
@TableField(select = false)
private Integer age;
// 是否為資料庫表欄位,設定為false,則插入時不會對其操作
@TableField(exist = false)
private String email;
}
3.3 自動填充屬性
步驟一:資料庫增加兩個屬性,create_time和update_time,

步驟二:物體類欄位屬性添加注解,
// 第一次添加填充
@TableField(fill= FieldFill.INSERT)
private Date createTime;
// 第一次添加的時候填充,但之后每次更新也會進行填充
@TableField(fill=FieldFill.INSERT_UPDATE)
private Date updateTime;
步驟三:撰寫處理器來處理這個注解
注意:在處理器類上方添加注解@Component!
package com.yixin.mybatis_plus.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component // 一定不要忘記把處理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入時的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill.....");
// setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
// 更新時的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
測驗:
@Test
void test9() {
// 我們沒有自定義id,它會幫我們自動生成id
User person =new User();
person.setName("一心同學呀");
person.setAge(20);
person.setEmail("test6@qq.com");
int result=personsMapper.insert(person);
System.out.println(result);// 受影響的行數
System.out.println(person);//可以發現,id會自動回填
}
資料庫

四、樂觀鎖
4.1 介紹
樂觀鎖 : 故名思意十分樂觀,它總是認為不會出現問題,無論干什么不去上鎖!如果出現了問題,再次更新值測驗
悲觀鎖:故名思意十分悲觀,它總是認為總是出現問題,無論干什么都會上鎖!再去操作!
樂觀鎖實作方式:
取出記錄時,獲取當前 version
更新時,帶上這個version
執行更新時, set version = newVersion where version = oldVersion
如果version不對,就更新失敗
代碼解釋:
樂觀鎖:1、先查詢,獲得版本號 version = 1
-- A
update person set name = "yixin", version = version + 1
where id = 2 and version = 1
-- B 執行緒搶先完成,這個時候 version = 2,會導致 A 修改失敗!
update person set name = "yixin", version = version + 1
where id = 2 and version = 1
4.2 注意事項
- 支持的資料型別只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整數型別下 newVersion = oldVersion + 1
- newVersion 會回寫到 entity 中
- 僅支持 updateById(id) 與 update(entity, wrapper) 方法
- 在 update(entity, wrapper) 方法下, wrapper 不能復用
4.3 實作樂觀鎖
步驟一:給資料庫中增加version欄位!

步驟二:物體類添加對應的欄位,
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
@Version //樂觀鎖Version注解
private Integer version;
}
步驟三:注冊組件,
package com.yixin.mybatis_plus.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
// 掃描我們的 mapper 檔案夾
@MapperScan("com.yixin.mybatis_plus.mapper")
@EnableTransactionManagement
@Configuration // 配置類
public class MyBatisPlusConfig {
// 注冊樂觀鎖插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4.4 測驗
(1)測驗樂觀鎖成功情況
@Test
void testOptimisticLocker() {
// 1、查詢用戶資訊
Person person=personMapper.selectById(1L);
// 2、修改用戶資訊
person.setName("一心同學");
int result=personMapper.updateById(person);
System.out.println(result);// 受影響的行數
}
結果:可以發現MP會自動幫我們進行樂觀鎖判定,

并且每修改一次,version就會+1,

(2)測驗失敗情況!多執行緒下!
@Test
void testOptimisticLocker2() {
// 執行緒 1
Person person=personMapper.selectById(3L);
person.setName("一心同學在寫博客");
// 模擬另外一個執行緒執行了插隊操作
Person person2=personMapper.selectById(3L);
person2.setName("一心同學在吃飯");
personMapper.updateById(person2);
int result=personMapper.updateById(person);// 如果沒有樂觀鎖就會覆寫插隊執行緒的值!
System.out.println(result);// 受影響的行數
}
資料庫:

也就是說我們的執行緒一沒有執行成功,
五、邏輯洗掉
5.1 介紹
物理洗掉 :從資料庫中直接移除
邏輯洗掉 :再資料庫中沒有被移除,而是通過一個變數來讓他失效! deleted = 0 => deleted = 1
管理員可以查看被洗掉的記錄!防止資料的丟失,類似于回收站!
5.2 實作邏輯洗掉
步驟一:在資料表中增加一個 deleted 欄位,

步驟二:物體類中增加屬性,
@TableLogic //邏輯洗掉private
Integer deleted;
步驟三:配置,
(1)在自定義配置類中添加邏輯洗掉組件
package com.yixin.mybatis_plus.config;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
// 掃描我們的 mapper 檔案夾
@MapperScan("com.yixin.mybatis_plus.mapper")
@EnableTransactionManagement
@Configuration // 配置類
public class MyBatisPlusConfig {
// 注冊樂觀鎖插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
// 邏輯洗掉組件!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
(2)在application.properties添加配置
# 配置邏輯洗掉
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
5.3 測驗
@Test
void test6() {
int result=personMapper.deleteById(5L);
System.out.println(result);// 受影響的行數
}
結果:

資料庫:
資料庫中并沒有洗掉,而是將deleted從0變為1,實作了邏輯洗掉,(其實就是更新操作)

小結
以上就是【一心同學】整理的【MyBatis-Plus】的常用【注解】講解,通過介紹和代碼實作,相信大家基本已經掌握了,這一塊的內容在我們平時的開發當中還是比較重要的,因為我們在開發當中用得最多的就是注解了,并且其能夠大大提高我們的【作業效率】,
如果這篇【文章】有幫助到你,希望可以給【一心同學】點個贊👍,創作不易,相比官方的陳述,我更喜歡用【通俗易懂】的文筆去講解每一個知識點,如果有對【后端技術】感興趣的小可愛,也歡迎關注?????? 【一心同學】??????,我將會給你帶來巨大的【識訓與驚喜】💕💕!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/413391.html
標籤:java
