Mybatis Plus 新增數(shù)據(jù)并返回主鍵 ID(圖文講解)
大家好,我是小哈。
本小節(jié)中,我們將學(xué)習(xí)如何通過 Mybatis Plus 框架給數(shù)據(jù)庫表新增數(shù)據(jù),主要內(nèi)容思維導(dǎo)圖如下:
Mybatis Plus 新增數(shù)據(jù)思維導(dǎo)圖
表結(jié)構(gòu)
為了演示新增數(shù)據(jù),在前面小節(jié)中,我們已經(jīng)定義好了一個用于測試的用戶表, 執(zhí)行腳本如下:
DROP TABLE IF EXISTS t_user;
CREATE TABLE `t_user` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵ID', `name` varchar(30) NOT NULL DEFAULT '' COMMENT '姓名', `age` int(11) NULL DEFAULT NULL COMMENT '年齡', `gender` tinyint(2) NOT NULL DEFAULT 0 COMMENT '性別,0:女 1:男', PRIMARY KEY (`id`) ) COMMENT = '用戶表';
定義實體類
定義一個名為?User
?實體類:
@Data
@TableName("t_user")
public class User {
/**
* 主鍵 ID, @TableId 注解定義字段為表的主鍵,type 表示主鍵類型,IdType.AUTO 表示隨著數(shù)據(jù)庫 ID 自增
*/
@TableId(type = IdType.AUTO) private Long id; /** * 姓名 */ private String name; /** * 年齡 */ private Integer age; /** * 性別 */ private Integer gender; }
講解一下實體類中用到的注解:
@TableName 表名注解
作用:標(biāo)識實體類對應(yīng)的表。
TIP :
- 當(dāng)實體類名稱和實際表名一致時,如實體名為?
User
, 表名為?user
?,可不用添加該注解,Mybatis Plus 會自動識別并映射到該表。- 當(dāng)實體類名稱和實際表名不一致時,如實體名為?
User
, 表名為?t_user
,需手動添加該注解,并填寫實際表名稱。
@TableId 主鍵注解
作用:聲明實體類中的主鍵對應(yīng)的字段。
屬性 | 類型 | 必須指定 | 默認(rèn)值 | 描述 |
---|---|---|---|---|
value | String | 否 | "" | 主鍵字段名 |
type | Enum | 否 | IdType.NONE | 指定主鍵類型 |
IdType 主鍵類型
值 | 描述 |
---|---|
AUTO | 數(shù)據(jù)庫 ID 自增 |
NONE | 無狀態(tài),該類型為未設(shè)置主鍵類型(默認(rèn)) |
INPUT | 插入數(shù)據(jù)前,需自行設(shè)置主鍵的值 |
ASSIGN_ID | 分配 ID(主鍵類型為 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator 的方法nextId (默認(rèn)實現(xiàn)類為DefaultIdentifierGenerator 雪花算法) |
ASSIGN_UUID | 分配 UUID,主鍵類型為 String(since 3.3.0),使用接口IdentifierGenerator 的方法nextUUID ?(默認(rèn) default 方法) |
分布式全局唯一 ID 長整型類型 (推薦使用?ASSIGN_ID ) |
|
32 位 UUID 字符串 (推薦使用?ASSIGN_UUID ) |
|
分布式全局唯一 ID 字符串類型 (推薦使用?ASSIGN_ID ) |
開始新增數(shù)據(jù)
測試表準(zhǔn)備好后,我們準(zhǔn)備開始演示新增數(shù)據(jù)。實際上,Mybatis Plus 對 Mapper 層和 Service 層都將常見的增刪改查操作都封裝好了,只需簡單的繼承,即可輕松搞定對數(shù)據(jù)的增刪改查,本文重點講解新增數(shù)據(jù)這塊。
Mapper 層
定義一個?UserMapper
?, 讓其繼承?BaseMapper
?:
public interface UserMapper extends BaseMapper<User> { }
然后,注入 Mapper :
@Autowired
private UserMapper userMapper;
BaseMapper
?提供的新增方法僅一個?insert()
?方法:
我們通過它測試一下添加數(shù)據(jù),并獲取主鍵 ID :
User user =new User();
user.setName("犬小哈");
user.setAge(30);
user.setGender(1);
userMapper.insert(user);
// 獲取插入數(shù)據(jù)的主鍵 ID Long id = user.getId(); System.out.println("id:" + id);
怎么樣,是不是非常簡單呢!
Service 層
Mybatis Plus 同樣也封裝了通用的 Service 層 CRUD 操作,并且提供了更豐富的方法。接下來,我們上手看 Service 層的代碼結(jié)構(gòu),如下圖:
定義 Service 層
先定義?UserService
?接口 ,讓其繼承自?IService
:
public interface UserService extends IService<User> { }
再定義實現(xiàn)類?UserServiceImpl
,讓其繼承自?ServiceImpl
, 同時實現(xiàn)?UserService
?接口,這樣就可以讓?UserService
?擁有了基礎(chǔ)通用的 CRUD 功能,當(dāng)然,實際開發(fā)中,業(yè)務(wù)會更加復(fù)雜,就需要向?IService
?接口自定義方法并實現(xiàn):
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { }
注入?UserService
?:
@Autowired
private UserService userService;
與 Mapper 層不同的是,Service 層的新增方法均以?save
?開頭,并且功能更豐富,來看看都提供了哪些方法:
新增數(shù)據(jù)共有 6 個方法
簡單解釋下每個方法的作用,以作了解:
// 新增數(shù)據(jù)
sava(T) : boolean
// 偽批量插入,實際上是通過 for 循環(huán)一條一條的插入
savaBatch(Collection<T>) : boolean
// 偽批量插入,int 表示批量提交數(shù),默認(rèn)為 1000 savaBatch(Collection<T>, int) : boolean // 新增或更新(單條數(shù)據(jù)) saveOrUpdate(T) : boolean // 批量新增或更新 saveOrUpdateBatch(Collection<T>) : boolean // 批量新增或更新(可指定批量提交數(shù)) saveOrUpdateBatch(Collection<T>, int) : boolean
大致看完后,上手測試一下。
sava(T)
簡單的新增數(shù)據(jù),示例代碼如下:
// 新增數(shù)據(jù)
// 實際執(zhí)行 SQL :INSERT INTO user ( name, age, gender ) VALUES ( '小哈 111', 30, 1 ) User user = new User(); user.setName("小哈 111"); user.setAge(30); user.setGender(1); boolean isSuccess = userService.save(user); // 返回主鍵ID Long id = user.getId(); System.out.println("isSuccess:" + isSuccess); System.out.println("主鍵 ID: " + id);
savaBatch(Collection)
偽批量插入,注意,命名雖然包含了批量的意思,但這不是真的批量插入,不信的話,我們來實際測試一下:
// 批量插入
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) { User user = new User(); user.setName("犬小哈" + i); user.setAge(i); user.setGender(1); users.add(user); } boolean isSuccess = userService.saveBatch(users); System.out.println("isSuccess:" + isSuccess);
執(zhí)行代碼,實際執(zhí)行的 SQL 如下:
TIP : 如何打印實際執(zhí)行的 SQL, 可參考之前小節(jié)的?《Mybatis Plus 打印 SQL 語句(包含執(zhí)行耗時)》?。
批量插入輸入 SQL 打印
可以看到,并不是?insert into user (xxx) values (xxx),(xxx),(xxx)
?這種批量形式,還是一條一條插入的。
批量新增源碼分析
我們來看下源碼, 內(nèi)部的saveBatch()
?方法默認(rèn)的批量提交閥值參數(shù),數(shù)值為 1000, 即達(dá)到 1000 條批量提交一次,繼續(xù)點進(jìn)去看::
源碼分析
public boolean saveBatch(Collection<T> entityList, int batchSize) { // 獲取預(yù)編譯的插入 SQL String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE); // for 循環(huán)執(zhí)行 insert return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> { sqlSession.insert(sqlStatement, entity); }); }
再看下?SqlMethod.INSERT_ONE
?這個枚舉,描述信息為插入一條數(shù)據(jù):
繼續(xù)往?executeBatch()
?方法里看,瞅瞅它這個批量到底是怎么處理的,具體每行代碼的意思,小哈都加了注釋:
public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) { // 斷言需要批處理數(shù)據(jù)集大小不等于1 Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]); // 判空數(shù)據(jù)集,若不為空,則開始執(zhí)行批量處理 return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, (sqlSession) -> { int size = list.size(); // 將批處理大小與傳入的操作集合大小進(jìn)行比較,取最小的那個 int idxLimit = Math.min(batchSize, size); int i = 1; // 迭代器循環(huán) for(Iterator var7 = list.iterator(); var7.hasNext(); ++i) { // 獲取當(dāng)前需要執(zhí)行的數(shù)據(jù)庫操作 E element = var7.next(); // 回調(diào) sqlSession.insert() 方法 consumer.accept(sqlSession, element); // 判斷是否達(dá)到需要批處理的閥值 if (i == idxLimit) { // 開始批處理,此方法執(zhí)行并清除緩存在 JDBC 驅(qū)動類中的執(zhí)行語句 sqlSession.flushStatements(); idxLimit = Math.min(idxLimit + batchSize, size); } } }); }
看完就明白了,相比較自己手動?for
?循環(huán)執(zhí)行插入,Mybatis Plus 這個偽批量插入性能會更好些,內(nèi)部會將每次的插入語句緩存起來,等到達(dá)到 1000 條的時候,才會統(tǒng)一推給數(shù)據(jù)庫,雖然最終在數(shù)據(jù)庫那邊還是一條一條的執(zhí)行 INSERT,但還是在和數(shù)據(jù)庫交互的 IO 上做了優(yōu)化。
savaBatch(Collection, int)
多了個?batchSize
?參數(shù),可以手動指定批處理的大小,即多少 SQL 操作執(zhí)行一次,默認(rèn)為 1000。
saveOrUpdate(T)
保存或者更新。即當(dāng)你需要執(zhí)行的數(shù)據(jù),數(shù)據(jù)庫中不存在時,就執(zhí)行插入操作:
// 實際執(zhí)行 SQL :INSERT INTO user ( name, age, gender ) VALUES ( '小小哈', 60, 1 ) User user = new User(); user.setName("小小哈"); user.setAge(60); user.setGender(1); userService.saveOrUpdate(user);
當(dāng)你需要執(zhí)行的數(shù)據(jù),數(shù)據(jù)庫中已存在時,就執(zhí)行更新操作??蚣苁侨绾闻袛嘣撚涗浭欠翊嬖谀?? 如設(shè)置了主鍵 ID,因為主鍵 ID 必須是唯一的,Mybatis Plus 會先執(zhí)行查詢操作,判斷數(shù)據(jù)是否存在,存在即執(zhí)行更新,否則,執(zhí)行插入操作:
User user =new User();
// 設(shè)置了主鍵字段
user.setId(21L);
user.setName("小小哈");
user.setAge(60); user.setGender(1); userService.saveOrUpdate(user);
具體執(zhí)行 SQL 如下:
saveOrUpdateBatch(Collection)
批量保存或者更新,示例代碼如下:文章來源:http://www.zghlxwxcb.cn/news/detail-780977.html
List<User> users =new ArrayList<>();
for (int i = 0; i < 5; i++) { User user = new User(); user.setId(Long.valueOf(i)); user.setName("犬小哈" + i); user.setAge(i+1); user.setGender(1); users.add(user); } userService.saveOrUpdateBatch(users);
saveOrUpdateBatch(Collection, int)
批量保存或者更新(可手動指定批量大小),示例代碼如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-780977.html
List<User> users =new ArrayList<>();
for (int i = 0; i < 5; i++) { User user = new User(); user.setId(Long.valueOf(i)); user.setName("犬小哈" + i); user.setAge(i+1); user.setGender(1); users.add(user); } userService.saveOrUpdateBatch(users, 100);
到了這里,關(guān)于spring boot集成mybatis-plus——Mybatis Plus 新增數(shù)據(jù)并返回主鍵 ID(圖文講解)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!