一、引入依赖
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version>
</dependency>
二、在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默认使用IdType.ID_WORKER 雪花算法 Long类型作为id,根据主键类型选择IdType
private Long id;
/** 名称 */
private String name;
/** 年龄 */
private Integer age;
/** 邮箱 */
private String email;
/** 创建时间 */
@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、默认使用雪花算法生成主键
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 { // 实现元对象处理器接口
// 获取当前日期
private Date getCurrentDateTime() {
return Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
}
// 插入元对象字段填充(用于插入时对公共字段的填充)
@Override
public void insertFill(MetaObject metaObject) {
log.info("插入元对象字段填充开始...");
// this.setFieldValByName(属性名称,默认值,metaObject); // 默认值类型 对应 实体类属性类型
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;
// 网上能找到该类
@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);
// 再进行修改操作才会对版本号version进行修改
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<User> users = mybatisPlusMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L, 4L, 666L));
users.forEach(System.out::println);
Map<String, Object> map = new HashMap<>();
map.put("age", 18);
System.out.println("------------333------------");
List<User> users2 = mybatisPlusMapper.selectByMap(map);
users2.forEach(System.out::println);
QueryWrapper<User> userWrapper = new QueryWrapper<>();
userWrapper.eq("name", "Jack");
userWrapper.isNull("create_time"); // column 这里填的是数据库中的字段名称
System.out.println("------------444------------");
List<User> users3 = mybatisPlusMapper.selectList(userWrapper);
users3.forEach(System.out::println);
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNull("create_time");
IPage<User> userIPage = new Page<>(2, 3);
System.out.println("------------555------------");
mybatisPlusMapper.selectPage(userIPage, wrapper);
userIPage.getRecords().forEach(System.out::println);
System.out.println("当前页:" + userIPage.getCurrent());
System.out.println("每页数据条数:" + userIPage.getSize());
System.out.println("总页数:" + userIPage.getPages());
System.out.println("总数据条数:" + userIPage.getTotal());
}
@Test
public void deleteTest() {
// 可以是直接删除一条数据,也可以是逻辑删除,需要看具体配置
mybatisPlusMapper.deleteById(1449654351730593792L);
}
}
/**
1、使用乐观锁需要修改版本号,引入插件后,每一次修改数据版本号都会加1(需要先将数据查出来版本号才会更改)
2、使用Mybatis-plus进行分页查询时,需要将"分页插件"注入容器当中
3、删除时比较特殊,请往下看
*/
四、使用乐观锁
1、乐观锁需要版本号,在数据库中添加 "版本号" 字段;
2、在实体类中添加 "版本号" 属性,并加上 "@version" 注解;
3、将OptimisticLockerInterceptor类注入容器中,该类会对版本号version进行自增操作;
4、代码实际操作,需要先查出该对象,再进行修改操作才会对版本号进行修改(见上述测试类中的updateTest()方法)。
五、字段值自动填充
1、在字段上添加相应注解,如:
@TableField(fill = FieldFill.INSERT) // 插入的时候自动填充该字段的值
@TableField(fill = FieldFill.INSERT_UPDATE) // 插入和修改的时候自动填充该字段的值
2、自定义一个类,实现元对象处理器接口"MetaObjectHandler",重写"insertFill"和"updateFill"方法,并将该类注入容器中
六、物理删除和逻辑删除
// 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
// 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
@Test
public void deleteTest() {
// 可以是直接删除一条数据,也可以是逻辑删除,需要看具体配置
mybatisPlusMapper.deleteById(1449654351730593792L);
}
1、如上代码,当不做任何配置时,会直接进行"物理删除";
2、若要实现"逻辑删除",需如下配置:
(1)在数据库中添加一个字段"deleted";
(2)在实体类中添加一个属性"deleted",并添加相应注解;
// value - 删除前的状态,delval - 删除后的状态
// 表示逻辑删除,加上该注解后,删除语句就会变成更新语句
@TableLogic(value = "0", delval = "1")
// @TableLogic
private Integer deleted;
(3)向容器中注入 "ISqlInjector" 类(逻辑删除插件)
/**
若使用 @TableLogic 而不是 @TableLogic(value = "0", delval = "1") 时,
此时可以在application.properties文件中配置逻辑删除的状态,也可以达到逻辑删除的效果,如下:
# 逻辑删除状态
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
*/
/**
测试删除方法后分析打印的sql语句,是一条update
注意:被删除数据的 deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作,如下日志
==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 1449654351730593792(Long)
<== Updates: 0
*/
七、统一返回的json时间格式
默认情况下json时间格式带有时区,并且是世界标准时间,和我们的时间差了八个小时。
可以在"application.properties"文件中进行配置,优化Date类型字段输出格式。
# 返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
八、SQL 执行性能分析插件(可选)
1、将SQL执行性能分析插件"PerformanceInterceptor"注入容器中
@Configuration
@MapperScan(value = "com.example.mapper")
@EnableTransactionManagement
public class TeacherConfig {
/**
* SQL 执行性能分析插件
* 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
*/
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100);//ms,超过此处设置的ms则sql不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
}
2、在application.properties文件中指定开发环境
spring.profiles.active=dev
/**
开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
*/
九、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、创建代码生成器
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、数据源配置
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"); // 根据哪张表生成
strategy.setNaming(NamingStrategy.underline_to_camel); // 数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); // 生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel); // 数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); // restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
/**
放到test包下,修改一些基本配置后,直接运行run()方法即可
*/