MybatisPlus中的insert操作詳解
MybatisPlus insert操作
在測試之前,我們思考一個問題,上個入門案例中,我們什么sql語句代碼都沒寫,但也能查詢出來數(shù)據(jù)。
是誰幫我們做了寫基本代碼的事情?肯定是MybatisPlus。
為了驗證并繼續(xù)向下學(xué)習(xí),我們開啟日志,打印在控制臺上。
1、開啟日志
只需在yml配置文件中,寫上:
mybatis-plus: ? configuration: ? ? log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2、測試插入的代碼
? ? @Test ? ? void testInsert() { ? ? ? ? UserEntity userEntity = new UserEntity(); ? ? ? ? userEntity.setName("pipizhen"); ? ? ? ? userEntity.setAge(10); ? ? ? ? userEntity.setEmail("ppz@qq.com"); ? ? ? ? int count = userMapper.insert(userEntity); ? ? ? ? System.out.println(count); ? ? ? ? System.out.println(userEntity); ? ? }
控制臺輸出:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2373ad99] was not registered for synchronization because synchronization is not active
2020-11-23 14:13:12.748 INFO 7392 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-11-23 14:13:13.028 INFO 7392 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@1977652583 wrapping com.mysql.cj.jdbc.ConnectionImpl@2a334bac] will not be managed by Spring
==> Preparing: INSERT INTO tbl_user ( id, name, email, age ) VALUES ( ?, ?, ?, ? )
==> Parameters: 1330756266048045058(Long), pipizhen(String), ppz@qq.com(String), 10(Integer)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2373ad99]
1
UserEntity(id=1330756266048045058, name=pipizhen, age=10, email=ppz@qq.com)
說明我們插入數(shù)據(jù)成功了,細心的人會發(fā)現(xiàn)我們并沒有指定id,但插入成功后,我們發(fā)現(xiàn)對象存在id。
肯定是主鍵自動生成的,沒錯,但是怎么生成一個這么大的數(shù)字呢?為什么不是在原有的記錄條數(shù)id在自增1呢?
這里數(shù)據(jù)庫插入的id的默認值為:全局唯一id。
全局唯一id可自行百度:分布式系統(tǒng)唯一id生成。
3、MybatisPlus使用的是雪花算法
原理:Twitter的雪花算法SnowFlake,使用Java語言實現(xiàn)。
可以了解一下:
SnowFlake算法產(chǎn)生的ID是一個64位的整型,結(jié)構(gòu)如下(每一部分用“-”符號分隔):
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
- 1位標(biāo)識部分,在java中由于long的最高位是符號位,正數(shù)是0,負數(shù)是1,一般生成的ID為正數(shù),所以為0;
- 41位時間戳部分,這個是毫秒級的時間,一般實現(xiàn)上不會存儲當(dāng)前的時間戳,而是時間戳的差值(當(dāng)前時間-固定的開始時間),這樣可以使產(chǎn)生的ID從更小值開始;41位的時間戳可以使用69年,(1L << 41) / (1000L606024365) = 69年;
- 10位節(jié)點部分,Twitter實現(xiàn)中使用前5位作為數(shù)據(jù)中心標(biāo)識,后5位作為機器標(biāo)識,可以部署1024個節(jié)點;
- 12位序列號部分,支持同一毫秒內(nèi)同一個節(jié)點可以生成4096個ID;
SnowFlake算法生成的ID大致上是按照時間遞增的,用在分布式系統(tǒng)中時,需要注意數(shù)據(jù)中心標(biāo)識和機器標(biāo)識必須唯一,這樣就能保證每個節(jié)點生成的ID都是唯一的?;蛟S我們不一定都需要像上面那樣使用5位作為數(shù)據(jù)中心標(biāo)識,5位作為機器標(biāo)識,可以根據(jù)我們業(yè)務(wù)的需要,靈活分配節(jié)點部分,如:若不需要數(shù)據(jù)中心,完全可以使用全部10位作為機器標(biāo)識;若數(shù)據(jù)中心不多,也可以只使用3位作為數(shù)據(jù)中心,7位作為機器標(biāo)識。
snowflake生成的ID整體上按照時間自增排序,并且整個分布式系統(tǒng)內(nèi)不會產(chǎn)生ID碰撞(由datacenter和workerId作區(qū)分),并且效率較高。據(jù)說:snowflake每秒能夠產(chǎn)生26萬個ID。
4、MybatisPlus中的主鍵生成策略
我們可以在@TableId注解中發(fā)現(xiàn)有個屬性IdType,這是一個枚舉類。
舊版本的枚舉值有AUTO, NONE, INPUT, ID_WORKER, UUID, ID_WORKER_STR;
新版本又增加了兩種,ASSIGN_ID,ASSIGN_UUID。
舊版本當(dāng)我們不指定主鍵生成類型時,即值為null時,默認使用ID_WORKER類型。
新版本默認為NONE,注解里等于跟隨全局,全局里約等于 INPUT。
(1)AUTO
:數(shù)據(jù)庫ID自增。
(2)NONE
:無狀態(tài),該類型為未設(shè)置主鍵類型(注解里等于跟隨全局,全局里約等于 INPUT)。
(3)INPUT
:insert前自行set主鍵值,即我們插入前,需要手動設(shè)置id。
(4)ASSIGN_ID
:分配ID(主鍵類型為Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默認實現(xiàn)類為DefaultIdentifierGenerator雪花算法)。
(5)ASSIGN_UUID
:分配UUID,主鍵類型為String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默認default方法)
(6)ID_WORKER
:分布式全局唯一ID 長整型類型(please use ASSIGN_ID)。
(7)UUID
:32位UUID字符串(please use ASSIGN_UUID)。
(8)ID_WORKER_STR
分布式全局唯一ID 字符串類型(please use ASSIGN_ID)
注意:最后三個在最新版本中,ID_WORKER,UUID,ID_WORKER_STR已經(jīng)被遺棄了,不建議使用。
5、測試不同的主鍵生成策略
(1)AUTO策略
我們修改實體類中的id注解為:@TableId(value = “id”, type = IdType.AUTO)
并修改數(shù)據(jù)庫中表tbl_user的id確定為自增。不然啟動會報錯:Field ‘id’ doesn’t have a default value.
測試之前,我們還需把表中那個id好長的記錄刪掉,并重啟MySQL軟件,我的是Navicat。目的防止緩存的影響。
測試程序還是上面那幾行代碼:
@Test ? ? void testInsert() { ? ? ? ? UserEntity userEntity = new UserEntity(); ? ? ? ? userEntity.setName("pipizhen"); ? ? ? ? userEntity.setAge(10); ? ? ? ? userEntity.setEmail("ppz@qq.com"); ? ? ? ? int count = userMapper.insert(userEntity); ? ? ? ? System.out.println(count); ? ? ? ? System.out.println(userEntity); ? ? }
控制臺的部分打印為:
1
UserEntity(id=6, name=pipizhen, age=10, email=ppz@qq.com)
我們發(fā)現(xiàn)確實是我們熟悉的id自增1。
(2)INPUT策略
需要我們手動設(shè)置id的值,這樣設(shè)置時,當(dāng)數(shù)據(jù)庫表的id設(shè)置了自增,插入時可設(shè)置id,也可不設(shè)置id。
當(dāng)數(shù)據(jù)庫表id沒有設(shè)置自增,那我們插入數(shù)據(jù)時就必須設(shè)置id,不然誰來幫我們設(shè)置id的值,大家都知道id存在主鍵約束。
(3)ASSIGN_ID策略
也是自動生成一個很長的Long型數(shù)字。
可以自己嘗試測試一下,只需改變實體類中注解中的IdType屬性值。
MybatisPlus坑insert方法
有天早上我的一個同事,突然跑來告訴我。我們某張表的自增ID變得很大。類似1173776258468638722 這種。這個當(dāng)然是不能接受的啊。
著手解決
然后就開始找問題的原因,一開始我想的是數(shù)據(jù)庫上的問題,我刪掉不合理的數(shù)據(jù),
alter table *** AUTO_INCREMENT=20
修改自增ID從20開始。手動插入數(shù)據(jù),居然OK。
那就說明,可能是我們代碼insert數(shù)據(jù)的時候存在的問題。我找到數(shù)據(jù)庫訪問層的insert語句處,發(fā)現(xiàn)使用的是mybatis-plus,網(wǎng)上查了一下關(guān)于這塊的東西,發(fā)現(xiàn)insert方法在配置的時候,可以指定自增ID的方式。
源碼中定義有以下幾種
public enum IdType { ? ? AUTO(0, "數(shù)據(jù)庫ID自增"), ? ? INPUT(1, "用戶輸入ID"), ? ? ID_WORKER(2, "全局唯一ID"), ? ? UUID(3, "全局唯一ID"), ? ? NONE(4, "該類型為未設(shè)置主鍵類型"), ? ? ID_WORKER_STR(5, "字符串全局唯一ID");
然后我就果斷手動配置了一下,
? ? @TableId(type = IdType.AUTO) ? ? private Long userId;
重啟測試,OK。
也是很奇怪為什么之前的那部分數(shù)據(jù)的自增ID都是沒問題的,突然出現(xiàn)這個,也是很困惑
總結(jié),出現(xiàn)這個問題的原因,還是因為自己技術(shù)不熟練啦~~
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
windows下vscode+vs2019開發(fā)JNI的示例
本文給大家普及windows下vscode+vs2019開發(fā)JNI的示例以及各個環(huán)節(jié)的注意事項,文章通過示例代碼圖文相結(jié)合給大家介紹的非常詳細,需要的朋友可以參考下2021-06-06springBoot整合shiro如何解決讀取不到@value值問題
這篇文章主要介紹了springBoot整合shiro如何解決讀取不到@value值問題,具有很好的參考價值,希望對大家有所幫助,2023-08-08