測(cè)試環(huán)境在上一篇MyBatis-Plus概述中搭建完成!
Mapper CRUD 接口
Insert
Delete
Update
Select
配置日志
我們現(xiàn)在所有的sql現(xiàn)在是不可見的侨嘀,我們希望知道它是怎么執(zhí)行的嫉拐,所以我們必須要看日志唇辨。配置配置文件開啟日志輸出。
# 配置日志 控制臺(tái)輸出
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
查看測(cè)試查詢?nèi)啃Ч?/p>
插入操作
userMapper.insert();
參數(shù)是實(shí)體類對(duì)象
// 測(cè)試插入
@Test
void testInsert() {
User user = new User();
user.setName("kylin");
user.setAge(3);
user.setEmail("zhang171346168@qq.com");
int result = userMapper.insert(user);//id會(huì)自動(dòng)生成全局唯一id
System.out.println(result);
}
運(yùn)行測(cè)試
發(fā)現(xiàn)自動(dòng)幫我們生成一個(gè)全局唯一主鍵ID值!
主鍵生成策略
由上可知满粗,當(dāng)我們不配主鍵ID時(shí),MyBatisPlus會(huì)幫我們自動(dòng)生成一個(gè)全局唯一的主鍵值愚争。哪它是按什么思路生成的呢映皆?我們能配置主鍵生成策略嗎?答案是可以的轰枝。
我們可以通過在實(shí)體類上的@TableId進(jìn)行配置生成策略
值 | 描述 |
---|---|
AUTO | 數(shù)據(jù)庫(kù)ID自增 |
NONE | 無(wú)狀態(tài),該類型為未設(shè)置主鍵類型(注解里等于跟隨全局,全局里約等于 INPUT) |
INPUT | insert前自行set主鍵值 |
ASSIGN_ID | 分配ID(主鍵類型為Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator 的方法nextId (默認(rèn)實(shí)現(xiàn)類為DefaultIdentifierGenerator 雪花算法) |
ASSIGN_UUID | 分配UUID,主鍵類型為String(since 3.3.0),使用接口IdentifierGenerator 的方法nextUUID (默認(rèn)default方法) |
ID_WORKER | 分布式全局唯一ID 長(zhǎng)整型類型(please use ASSIGN_ID ) |
UUID | 32位UUID字符串(please use ASSIGN_UUID ) |
ID_WORKER_STR | 分布式全局唯一ID 字符串類型(please use ASSIGN_ID ) |
默認(rèn)值為ID_WORKER 全局唯一id捅彻。也就是上文生成的。(MyBatisPlus新版發(fā)生改變例如3.3.1)
其采用的算法是雪花算法
snowflake是Twitter開源的分布式ID生成算法鞍陨,結(jié)果是一個(gè)long型的ID步淹。其核心思想是:使用41bit作為 毫秒數(shù)从隆,10bit作為機(jī)器的ID(5個(gè)bit是數(shù)據(jù)中心,5個(gè)bit的機(jī)器ID)缭裆,12bit作為毫秒內(nèi)的流水號(hào)(意味 著每個(gè)節(jié)點(diǎn)在每毫秒可以產(chǎn)生 4096 個(gè) ID)键闺,最后還有一個(gè)符號(hào)位,永遠(yuǎn)是0澈驼⌒猎铮可以保證幾乎全球唯 一!
主鍵自增
以配置主鍵自增為例缝其。
1.首先我們要在實(shí)體類主鍵字段上加上@TableId(type = IdType.AUTO)
2.主鍵自增需要修改數(shù)據(jù)庫(kù)字段為自增
3.再次測(cè)試插入
此時(shí)的ID值則在原來(lái)去基礎(chǔ)上自增1.其他主鍵策略修改type值就可以了挎塌。
更新操作
userMapper.updateById();
注意參數(shù)是實(shí)體類對(duì)象,通過id作為條件進(jìn)行更新
測(cè)試之前將主鍵生成策略改為input手動(dòng)輸入
編寫測(cè)試
@Test
void testUpdate() {
User user = new User();
user.setId(5L);
user.setName("kylin");
user.setAge(12);
user.setEmail("zhang171346168@qq.com");
int i = userMapper.updateById(user);
System.out.println(i);
}
自動(dòng)填充
創(chuàng)建時(shí)間内边、修改時(shí)間榴都!這些個(gè)操作一遍都是自動(dòng)化完成的,我們不希望手動(dòng)更新漠其!
阿里巴巴開發(fā)手冊(cè):所有的數(shù)據(jù)庫(kù)表:gmt_create缭贡、gmt_modified幾乎所有的表都要配置上!而且需 要自動(dòng)化辉懒!
{% note success %}
方式一:數(shù)據(jù)庫(kù)級(jí)別(工作中不允許你修改數(shù)據(jù)庫(kù))
{% endnote %}
1阳惹、在表中新增字段 create_time, update_time
2.再次測(cè)試插入方法前,我們需要先把實(shí)體類的屬性與字段同步眶俩!
MyBatisPlus是默認(rèn)開啟駝峰命名的莹汤。也就是實(shí)體類中屬性createTime對(duì)應(yīng)字段create_time。如果數(shù)據(jù)庫(kù)中為create_time為createTime則會(huì)出現(xiàn)映射錯(cuò)誤颠印。
如果出現(xiàn)上面這種情況則需要配置MyBatisPlus的配置文件纲岭。關(guān)閉駝峰命名
mybatis-plus.configuration.map-underscore-to-camel-case=false
測(cè)試插入方法
3.插入成功后查看數(shù)據(jù)庫(kù)
發(fā)現(xiàn)數(shù)據(jù)庫(kù)中已經(jīng)更新了創(chuàng)建時(shí)間和更新時(shí)間。
注意:SpringBoot配置數(shù)據(jù)庫(kù)時(shí)時(shí)區(qū)為UTC會(huì)造成寫入數(shù)據(jù)庫(kù)時(shí)與中國(guó)北京時(shí)間相差8小時(shí)线罕。這時(shí)候我們就要修改時(shí)區(qū)為serverTimezone=GMT%2B8
{% note success %}
方式二:代碼級(jí)別
{% endnote %}
1.刪除數(shù)據(jù)庫(kù)的默認(rèn)值止潮、更新操作!(navicat中把這兩欄刪掉,再重新創(chuàng)建)
2.實(shí)體類字段屬性上需要增加注解@TableField
根據(jù)實(shí)際情況钞楼。updateTime應(yīng)在對(duì)其進(jìn)行任何操作時(shí)都要更新時(shí)間喇闸。所以要在插入和更新時(shí)都更新改字段。
3.編寫處理器來(lái)處理這個(gè)注解,在handle包下創(chuàng)建一個(gè)MyMetaObjectHandler 類實(shí)現(xiàn) MetaObjectHandler接口询件,重寫方法燃乍。
4、測(cè)試插入
5.測(cè)試更新
查看數(shù)據(jù)庫(kù)發(fā)現(xiàn)改用戶的更新時(shí)間發(fā)生改變宛琅。成功刻蟹!
樂觀鎖
{% note info %}
樂觀鎖 : 故名思意十分樂觀,它總是認(rèn)為不會(huì)出現(xiàn)問題嘿辟,無(wú)論干什么不去上鎖舆瘪!如果出現(xiàn)了問題片效, 再次更新值測(cè)試。
{% endnote %}
{% note warning %}
悲觀鎖:故名思意十分悲觀英古,它總是認(rèn)為總是出現(xiàn)問題淀衣,無(wú)論干什么都會(huì)上鎖!再去操作哺呜!
{% endnote %}
樂觀鎖實(shí)現(xiàn)方式
- 取出記錄時(shí),獲取當(dāng)前 version
- 更新時(shí)箕戳,帶上這個(gè)version
- 執(zhí)行更新時(shí)某残, set version = newVersion where version = oldVersion
- 如果version不對(duì),就更新失敗
{% note success %}
樂觀鎖插件測(cè)試
{% endnote %}
1.給數(shù)據(jù)庫(kù)中增加version字段陵吸!
2.我們實(shí)體類加對(duì)應(yīng)的字段玻墅。使用@Version
注解
3.編寫MybatisPlus配置類,注冊(cè)組件壮虫。
//@MapperScan("com.kylin.mapper")//掃描mapper文件夾
@EnableTransactionManagement//自動(dòng)管理事務(wù)
@Configuration//配置類
public class MybatisPlusConfig {
//注冊(cè)樂觀鎖插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4.測(cè)試一下
//測(cè)試樂觀鎖
@Test
void testOptimisticLocker() {
//1.查詢用戶信息
User user = userMapper.selectById(1L);
//2.修改用戶信息
user.setName("kylin");
user.setEmail("zhang171346168@qq.com");
//3.執(zhí)行更新操作
int i = userMapper.updateById(user);
System.out.println(i);
}
正常更新~
5.模擬另一個(gè)線程執(zhí)行了插隊(duì)操作測(cè)試
//測(cè)試樂觀鎖失敗~多線程下
@Test
void testOptimisticLocker2() {
//線程1
User user = userMapper.selectById(1L);
user.setName("kylin111");
user.setEmail("zhang171346168@qq.com");
//模擬另一個(gè)線程執(zhí)行了插隊(duì)操作
User user2 = userMapper.selectById(1L);
user2.setName("kylin222");
user2.setEmail("zhang171346168@qq.com");
//執(zhí)行更新操作
userMapper.updateById(user2);
userMapper.updateById(user);//如果沒有樂觀鎖就會(huì)覆蓋插隊(duì)線程的值
}
查詢操作
userMapper.selectById()
@Test
void testSelectById(){
User user = userMapper.selectById(1L);
System.out.println(user);
}
批量查詢userMapper.selectBatchIds()
//測(cè)試批量查詢
@Test
void testSelectByBatchId(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1,2,3));
users.forEach(System.out::println);
}
按條件查詢之一 通過mapuserMapper.selectByMap()
//測(cè)試條件查詢之一 通過map
@Test
void testSelectByBatchIds(){
HashMap<String,Object> map = new HashMap<>();
//自定義查詢
map.put("name","kylin");
map.put("age",3);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
分頁(yè)查詢
進(jìn)行分頁(yè)查詢可以使用原始的limit進(jìn)行分頁(yè)澳厢,或者使用pageHelper第三方插件。而MaBatisPlus也內(nèi)置了分頁(yè)插件囚似。
1.在MybatisPlus的配置類中注冊(cè)攔截器組件
//注冊(cè)分頁(yè)插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
2.測(cè)試剩拢。直接使用Page對(duì)象即可! userMapper.selectPage(page,null);//條件表達(dá)式為空
//測(cè)試分頁(yè)查詢
@Test
void testPage(){
//參數(shù)一:當(dāng)前頁(yè) 參數(shù)二:頁(yè)面大小
Page<User> page = new Page<>(2,5);
userMapper.selectPage(page,null);//條件表達(dá)式為空
page.getRecords().forEach(System.out::println);
}
刪除操作
根據(jù) id 刪除記錄userMapper.deleteById()
//測(cè)試刪除饶唤。根據(jù)id刪除
@Test
void testDeleteById(){
userMapper.deleteById(1251338727926538241L);
}
通過id批量刪除userMapper.deleteBatchIds()
//通過id批量刪除
@Test
void testDeleteBatchId(){
userMapper.deleteBatchIds(Arrays.asList(1251338727926538242L,1251338727926538243L));
}
通過map刪除userMapper.deleteByMap()
//通過map刪除
@Test
void testDeleteMap(){
HashMap<String,Object> map = new HashMap<>();
map.put("name","kylin222");
userMapper.deleteByMap(map);
}
邏輯刪除
{% note info %}
物理刪除 :從數(shù)據(jù)庫(kù)中直接移除
邏輯刪除 :再數(shù)據(jù)庫(kù)中沒有被移除徐伐,而是通過一個(gè)變量來(lái)讓他失效! deleted = 0 => deleted = 1
{% endnote %}
應(yīng)用場(chǎng)景:管理員可以查看被刪除的記錄募狂!防止數(shù)據(jù)的丟失办素,類似于回收站!
1.在數(shù)據(jù)表中增加一個(gè) deleted 字段
2.實(shí)體類中增加屬性祸穷。通過@TableLogic
3.在MybatisPlus配置類中注冊(cè)邏輯刪除性穿。3.1.1不用注冊(cè)Bean
//邏輯刪除組件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
4.在SpringBoot配置文件中配置邏輯刪除的默認(rèn)值
#配置邏輯刪除 默認(rèn)為0 邏輯刪除后為1
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
5.通過刪除操作進(jìn)行測(cè)試
在使用查詢?nèi)坎僮鳎纯词欠衲懿樵兊酱藯l記錄雷滚。
性能分析插件
我們?cè)谄綍r(shí)的開發(fā)中需曾,會(huì)遇到一些慢sql。druid數(shù)據(jù)源也是有性能分析的祈远。
作用:性能分析攔截器胯舷,用于輸出每條 SQL 語(yǔ)句及其執(zhí)行時(shí)間 MP也提供性能分析插件,如果超過這個(gè)時(shí)間就停止運(yùn)行绊含!
性能分析是需要消耗系統(tǒng)性能的桑嘶,所以設(shè)置當(dāng)處于開發(fā)環(huán)境dev,和測(cè)試環(huán)境test中開啟躬充。
1.配置MyBatis配置類注冊(cè)插件
2.測(cè)試逃顶。為了展示效果設(shè)置了sql語(yǔ)句運(yùn)行超過1毫米就不執(zhí)行讨便。隨便點(diǎn)擊一個(gè)測(cè)試
使用性能分析插件能幫我們直觀的展示Sql語(yǔ)句運(yùn)行的效率~