MyBatis-Plus整合SpringBoot 快速上手,值得收藏?。?!

MyBatis-Plus 是一個為了簡化開發(fā)效率而生的 MyBatis 增強工具,在 MyBatis 的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生。其整合到 Spring Boot 項目中,可以讓開發(fā)過程更加便捷。

一、引入依賴


com.baomidou

mybatis-plus-boot-starter

3.5.5

二、在application.properties中配置日志打印

# mybatis日志

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

三、代碼案例

(1)實體類

package com.example.entity;

import com.baomidou.mybatisplus.annotation.*;

import lombok.*;

import java.io.Serializable;

import java.util.Date;

@Data

public class User implements Serializable {

/** 主鍵 */

@TableId(type = IdType.ID_WORKER) // mybatis-plus默認(rèn)使用IdType.ID_WORKER 雪花算法 Long類型作為id,根據(jù)主鍵類型選擇IdType

private Long id;

/** 名稱 */

private String name;

/** 年齡 */

private Integer age;

/** 郵箱 */

private String email;

/** 創(chuàng)建時間 */

@TableField(fill = FieldFill.INSERT) // 插入的時候自動填充該字段的值

private Date createTime;

/** 修改時間 */

@TableField(fill = FieldFill.INSERT_UPDATE) // 插入和修改的時候自動填充該字段的值

private Date updateTime;

@TableField(fill = FieldFill.INSERT) // 插入的時候自動填充該字段的值

@Version // 樂觀鎖版本

private Integer version;

}

/**

mybatis-plus功能:

1、默認(rèn)使用雪花算法生成主鍵

2、支持字段值自動填充

*/

(2)配置類

package com.example.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;

import org.mybatis.spring.annotation.MapperScan;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration

@MapperScan(value = "com.example.mapper")

@EnableTransactionManagement

public class MybatisPlusConfig {

/**

* 樂觀鎖插件

* @return OptimisticLockerInterceptor

*/

@Bean

public OptimisticLockerInterceptor optimisticLockerInterceptor() {

return new OptimisticLockerInterceptor();

}

/**

* 分頁插件

* @return PaginationInterceptor

*/

@Bean

public PaginationInterceptor paginationInterceptor() {

return new PaginationInterceptor();

}

/**

* 邏輯刪除時用到

* @return ISqlInjector

*/

@Bean

public ISqlInjector sqlInjector() {

return new LogicSqlInjector();

}

}

(3)元對象處理類

package com.example.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.time.LocalDateTime;

import java.time.ZoneId;

import java.util.Date;

@Component

@Slf4j

public class MybatisPlusMetaObjectHandler implements MetaObjectHandler { // 實現(xiàn)元對象處理器接口

// 獲取當(dāng)前日期

private Date getCurrentDateTime() {

return Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());

}

// 插入元對象字段填充(用于插入時對公共字段的填充)

@Override

public void insertFill(MetaObject metaObject) {

log.info("插入元對象字段填充開始...");

// this.setFieldValByName(屬性名稱,默認(rèn)值,metaObject); // 默認(rèn)值類型 對應(yīng) 實體類屬性類型

this.setFieldValByName("createTime", getCurrentDateTime(), metaObject);

this.setFieldValByName("updateTime", getCurrentDateTime(), metaObject);

this.setFieldValByName("version", 1, metaObject);

log.info("插入元對象字段填充完成...");

}

// 更新元對象字段填充(用于更新時對公共字段的填充)

@Override

public void updateFill(MetaObject metaObject) {

log.info("更新元對象字段填充開始...");

this.setFieldValByName("updateTime", getCurrentDateTime(), metaObject);

log.info("更新元對象字段填充完成...");

}

}

(4)測試類

package com.example;

import com.baomidou.mybatisplus.core.conditions.Wrapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.core.metadata.IPage;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.example.entity.User;

import com.example.mapper.MybatisPlusMapper;

import com.example.util.IdWorker;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;

@RunWith(SpringRunner.class)

@SpringBootTest

public class MybatisPlusTest {

// 逆向生成的類

@Autowired

private MybatisPlusMapper mybatisPlusMapper;

// 網(wǎng)上能找到該類

@Autowired

private IdWorker idWorker;

@Test

public void insertTest() {

User user = new User();

user.setId(idWorker.nextId());

user.setName("xxxxx");

user.setAge(18);

user.setEmail("xxx@qq.com");

int result = mybatisPlusMapper.insert(user);

System.out.println("result = " + result);

System.out.println("id = " + user.getId());

System.out.println(user);

}

@Test

public void updateTest() {

// 需要先查出該對象

User user = mybatisPlusMapper.selectById(1449705947919306752L);

user.setName("小哆啦");

user.setUpdateTime(null);

// 再進(jìn)行修改操作才會對版本號version進(jìn)行修改

mybatisPlusMapper.updateById(user);

}

@Test

public void selectTest() {

System.out.println("------------111------------");

User user = mybatisPlusMapper.selectById(1449705947919306752L);

Optional.ofNullable(user).ifPresent(System.out::println);

System.out.println("------------222------------");

List users = mybatisPlusMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L, 4L, 666L));

users.forEach(System.out::println);

Map map = new HashMap<>();

map.put("age", 18);

System.out.println("------------333------------");

List users2 = mybatisPlusMapper.selectByMap(map);

users2.forEach(System.out::println);

QueryWrapper userWrapper = new QueryWrapper<>();

userWrapper.eq("name", "Jack");

userWrapper.isNull("create_time"); // column 這里填的是數(shù)據(jù)庫中的字段名稱

System.out.println("------------444------------");

List users3 = mybatisPlusMapper.selectList(userWrapper);

users3.forEach(System.out::println);

QueryWrapper wrapper = new QueryWrapper<>();

wrapper.isNull("create_time");

IPage userIPage = new Page<>(2, 3);

System.out.println("------------555------------");

mybatisPlusMapper.selectPage(userIPage, wrapper);

userIPage.getRecords().forEach(System.out::println);

System.out.println("當(dāng)前頁:" + userIPage.getCurrent());

System.out.println("每頁數(shù)據(jù)條數(shù):" + userIPage.getSize());

System.out.println("總頁數(shù):" + userIPage.getPages());

System.out.println("總數(shù)據(jù)條數(shù):" + userIPage.getTotal());

}

@Test

public void deleteTest() {

// 可以是直接刪除一條數(shù)據(jù),也可以是邏輯刪除,需要看具體配置

mybatisPlusMapper.deleteById(1449654351730593792L);

}

}

/**

1、使用樂觀鎖需要修改版本號,引入插件后,每一次修改數(shù)據(jù)版本號都會加1(需要先將數(shù)據(jù)查出來版本號才會更改)

2、使用Mybatis-plus進(jìn)行分頁查詢時,需要將"分頁插件"注入容器當(dāng)中

3、刪除時比較特殊,請往下看

*/

四、使用樂觀鎖

1、樂觀鎖需要版本號,在數(shù)據(jù)庫中添加 "版本號" 字段;

2、在實體類中添加 "版本號" 屬性,并加上 "@version" 注解;

3、將OptimisticLockerInterceptor類注入容器中,該類會對版本號version進(jìn)行自增操作;

4、代碼實際操作,需要先查出該對象,再進(jìn)行修改操作才會對版本號進(jìn)行修改(見上述測試類中的updateTest()方法)。

五、字段值自動填充

1、在字段上添加相應(yīng)注解,如:

@TableField(fill = FieldFill.INSERT) // 插入的時候自動填充該字段的值

@TableField(fill = FieldFill.INSERT_UPDATE) // 插入和修改的時候自動填充該字段的值

2、自定義一個類,實現(xiàn)元對象處理器接口"MetaObjectHandler",重寫"insertFill"和"updateFill"方法,并將該類注入容器中

六、物理刪除和邏輯刪除

// 物理刪除:真實刪除,將對應(yīng)數(shù)據(jù)從數(shù)據(jù)庫中刪除,之后查詢不到此條被刪除數(shù)據(jù)

// 邏輯刪除:假刪除,將對應(yīng)數(shù)據(jù)中代表是否被刪除字段狀態(tài)修改為“被刪除狀態(tài)”,之后在數(shù)據(jù)庫中仍舊能看到此條數(shù)據(jù)記錄

@Test

public void deleteTest() {

// 可以是直接刪除一條數(shù)據(jù),也可以是邏輯刪除,需要看具體配置

mybatisPlusMapper.deleteById(1449654351730593792L);

}

1、如上代碼,當(dāng)不做任何配置時,會直接進(jìn)行"物理刪除";

2、若要實現(xiàn)"邏輯刪除",需如下配置:

(1)在數(shù)據(jù)庫中添加一個字段"deleted";

(2)在實體類中添加一個屬性"deleted",并添加相應(yīng)注解;

// value - 刪除前的狀態(tài),delval - 刪除后的狀態(tài)

// 表示邏輯刪除,加上該注解后,刪除語句就會變成更新語句

@TableLogic(value = "0", delval = "1")

// @TableLogic

private Integer deleted;

(3)向容器中注入 "ISqlInjector" 類(邏輯刪除插件)

/**

若使用 @TableLogic 而不是 @TableLogic(value = "0", delval = "1") 時,

此時可以在application.properties文件中配置邏輯刪除的狀態(tài),也可以達(dá)到邏輯刪除的效果,如下:

# 邏輯刪除狀態(tài)

mybatis-plus.global-config.db-config.logic-delete-value=1

mybatis-plus.global-config.db-config.logic-not-delete-value=0

*/

/**

測試刪除方法后分析打印的sql語句,是一條update

注意:被刪除數(shù)據(jù)的 deleted 字段的值必須是 0,才能被選取出來執(zhí)行邏輯刪除的操作,如下日志

==> ?Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0

==> Parameters: 1449654351730593792(Long)

<== ? ?Updates: 0

*/

七、統(tǒng)一返回的json時間格式

默認(rèn)情況下json時間格式帶有時區(qū),并且是世界標(biāo)準(zhǔn)時間,和我們的時間差了八個小時。

可以在"application.properties"文件中進(jìn)行配置,優(yōu)化Date類型字段輸出格式。

# 返回json的全局時間格式

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

spring.jackson.time-zone=GMT+8

八、SQL 執(zhí)行性能分析插件(可選)

1、將SQL執(zhí)行性能分析插件"PerformanceInterceptor"注入容器中

@Configuration

@MapperScan(value = "com.example.mapper")

@EnableTransactionManagement

public class TeacherConfig {

/**

* SQL 執(zhí)行性能分析插件

* 開發(fā)環(huán)境使用,線上不推薦。 maxTime 指的是 sql 最大執(zhí)行時長

*/

@Bean

@Profile({"dev","test"})// 設(shè)置 dev test 環(huán)境開啟

public PerformanceInterceptor performanceInterceptor() {

PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();

performanceInterceptor.setMaxTime(100);//ms,超過此處設(shè)置的ms則sql不執(zhí)行

performanceInterceptor.setFormat(true);

return performanceInterceptor;

}

}

2、在application.properties文件中指定開發(fā)環(huán)境

spring.profiles.active=dev

/**

開發(fā)環(huán)境使用,線上不推薦。 maxTime 指的是 sql 最大執(zhí)行時長

*/

九、MyBatis-Plus代碼生成器

package com.example;

import com.baomidou.mybatisplus.annotation.DbType;

import com.baomidou.mybatisplus.annotation.IdType;

import com.baomidou.mybatisplus.generator.AutoGenerator;

import com.baomidou.mybatisplus.generator.config.DataSourceConfig;

import com.baomidou.mybatisplus.generator.config.GlobalConfig;

import com.baomidou.mybatisplus.generator.config.PackageConfig;

import com.baomidou.mybatisplus.generator.config.StrategyConfig;

import com.baomidou.mybatisplus.generator.config.rules.DateType;

import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import org.junit.Test;

public class CodeGenerator {

@Test

public void run() {

// 1、創(chuàng)建代碼生成器

AutoGenerator mpg = new AutoGenerator();

// 2、全局配置

GlobalConfig gc = new GlobalConfig();

String projectPath = System.getProperty("user.dir");

gc.setOutputDir(projectPath + "/src/main/java");

gc.setAuthor("author");

gc.setOpen(false); // 生成后是否打開資源管理器

gc.setFileOverride(true); // 重新生成時文件是否覆蓋

gc.setServiceName("%sService");?? ?// 去掉Service接口的首字母I

gc.setIdType(IdType.ID_WORKER); // 主鍵策略

gc.setDateType(DateType.ONLY_DATE); // 定義生成的實體類中日期類型

gc.setSwagger2(true); // 開啟Swagger2模式

? ? ? ? mpg.setGlobalConfig(gc);

// 3、數(shù)據(jù)源配置

DataSourceConfig dsc = new DataSourceConfig();

dsc.setUrl("jdbc:mysql://localhost:3306/database_name");

dsc.setDriverName("com.mysql.cj.jdbc.Driver");

dsc.setUsername("root");

dsc.setPassword("123456");

dsc.setDbType(DbType.MYSQL);

mpg.setDataSource(dsc);

// 4、包配置

PackageConfig pc = new PackageConfig();

pc.setModuleName("module-xxx"); // 模塊名

pc.setParent("com.example");

pc.setController("controller");

pc.setEntity("entity");

pc.setService("service");

pc.setMapper("mapper");

mpg.setPackageInfo(pc);

// 5、策略配置

StrategyConfig strategy = new StrategyConfig();

strategy.setInclude("t_user"); // 根據(jù)哪張表生成

strategy.setNaming(NamingStrategy.underline_to_camel); // 數(shù)據(jù)庫表映射到實體的命名策略

strategy.setTablePrefix(pc.getModuleName() + "_"); // 生成實體時去掉表前綴

strategy.setColumnNaming(NamingStrategy.underline_to_camel); // 數(shù)據(jù)庫表字段映射到實體的命名策略

strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter鏈?zhǔn)讲僮?/p>

strategy.setRestControllerStyle(true); // restful api風(fēng)格控制器

strategy.setControllerMappingHyphenStyle(true); //url中駝峰轉(zhuǎn)連字符

? ? ? ? mpg.setStrategy(strategy);

// 6、執(zhí)行

mpg.execute();

}

}

/**

放到test包下,修改一些基本配置后,直接運行run()方法即可

*/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容