一、引入依赖

<!-- 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()方法即可
*/


MyBatis-Plus整合SpringBoot及使用_MyBatis-Plus的简单使用