> 文档中心 > 史上最简单的mybatis-plus快速入门

史上最简单的mybatis-plus快速入门


mybatis-plus快速入门

介绍:
Mybatis-Plus(简称MP)是一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发,提高效率而生。
数据库表:

-- 创建表CREATE TABLE tbl_employee(   id INT(11) PRIMARY KEY AUTO_INCREMENT,   last_name VARCHAR(50),   email VARCHAR(50),   gender CHAR(1),   age INT);INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Tom','tom@atguigu.com',1,22);INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Jerry','jerry@atguigu.com',0,25);INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Black','black@atguigu.com',1,30);INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('White','white@atguigu.com',0,35);

一:实体类的配置

mybatis-plus常用的实体类注解

@TableName:对数据表名注解@TableId:表主键标识@TableId(value = "id", type = IdType.AUTO):自增@TableId(value = "id", type = IdType.ID_WORKER_STR):分布式全局唯一ID字符串类型@TableId(value = "id", type = IdType.UUID)32UUID字符串@TableField:表字段标识@TableField(exist = false):表示该属性不为数据库表字段,但又是必须使用的。@Version:乐观锁注解、标记@EnumValue:通枚举类注解@TableLogic:表字段逻辑处理注解(逻辑删除)
@Data@AllArgsConstructor@NoArgsConstructor@TableName("tbl_employee")public class Employee {    @TableId(value = "id",type= IdType.AUTO)    private Integer id;    @TableField("last_name")    private String lastName;    private String email;    private Integer gender;    private Integer age;}

二:增删查改的实现

让编写的mapper接口继承BaseMapper接口

/** * 基于Mybatis‐plus实现: 让XxxMapper接口继承 BaseMapper接口即可. * BaseMapper : 泛型指定的就是当前Mapper接口所操作的实体类类型 */@Repositorypublic interface EmployeeMapper extends BaseMapper<Employee> {    }

测试:

@SpringBootTest@RunWith(SpringRunner.class)public class EmployeeMapperTest {    @Autowired    private EmployeeMapper employeeMapper;    @Test    public void select(){ Object o = employeeMapper.selectById(1); System.out.println(o);    }    @Test    public void insert(){ Employee employee = new Employee(null, "xushu", "dasda", 1, 211); employeeMapper.insert(employee);    }    @Test    public void update(){ Employee employee = new Employee(4, "xushu", "dasda", 1, 211); employeeMapper.updateById(employee);    }    @Test    public void delete(){ Employee employee = new Employee(4, "xushu", "dasda", 1, 211); int i = employeeMapper.deleteById(4);    }    @Test    public void selectList(){ HashMap<String, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("gender",1); List<Employee> employees = employeeMapper.selectByMap(objectObjectHashMap); System.out.println(employees);    }}

三:条件构造器Wrapper

在这里插入图片描述
(1)Wrapper :条件构造抽象类,最顶端父类,抽象类中提供3个方法以及其他方法.
(2)AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件,QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
(3)AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。 (4)LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper (5)LambdaUpdateWrapper : Lambda 更新封装Wrapper
(6)QueryWrapper : Entity 对象封装操作类,不是用lambda语法,自身的内部属性 entity 也用于生成 where 条件 该类的重要方法:

具体用法请查该地址:mybatis-plus条件构造器
样例:

@Test    public void selectWrapper(){ QueryWrapper<Employee> wrapper = new QueryWrapper<>(); wrapper.  between("age",18,30); List<Employee> list = employeeService.list(wrapper); System.out.println(employeeService.list(wrapper));    }    @Test    public void updateWrapper(){ UpdateWrapper<Employee> wrapper = new UpdateWrapper<>(); wrapper.set("last_name","wang").eq("id",1); boolean update = employeeService.update(wrapper); System.out.println(update); selectWrapper();    }    // 使用lambda表达式查询    @Test    public void lambdaSelect(){ QueryWrapper<Employee> wrapper = new QueryWrapper<>(); wrapper.lambda()  .select(Employee::getLastName,Employee::getAge)  .eq(Employee::getLastName,"wang"); System.out.println(employeeService.list(wrapper));    }

四:全局id生成策略

在yaml文件中使用配置

mybatis-plus:  configuration:  // 开启驼峰命名法    map-underscore-to-camel-case: true  global-config:    db-config:    // 设置全局的主键自增,不需要给每一个都配置      id-type: auto

测试样例

   @Test    public void insertWrapper(){ Employee employee = new Employee(null,"hei","dasd",1,32); employeeService.save(employee); System.out.println(employee);    }

五:MyBatis-Plus逻辑删除

物理删除: 在删除的时候直接将数据从数据库干掉DELTE
逻辑删除: 从逻辑层面控制删除,通常会在表里添加一个逻辑删除的字段比如 enabled 、is_delete ,数据默认是有效的(值为1), 当用户删除时将数据修改UPDATE 0, 在查询的时候就只查where enabled=1.

方法一:在数据库中增加一个判断是否删除的字段

@TableLogic()    private Integer enabled;

mybatis-plus对于是否删除的默认判断:0是未删除,1是已删除 由于不太符合常用的规则,可以自定义是否删除的标志

/**     * 未删除的数据为1,已删除的数据为0     */    @TableLogic(value = "1",delval = "0")    private Integer enabled;

方法二:在yaml文件中配置是否删除

mybatis-plus:  configuration:    map-underscore-to-camel-case: true  global-config:    db-config:      id-type: auto      logic-delete-field: enabled  #判断是否删除的字段,逻辑删除的字段      logic-not-delete-value: 1  #没有删除1      logic-delete-value: 0   #已删除是0

六:MyBatis-Plus自动填充

在表中添加 create_date和modify_date两个字段,如何做到自动填充数据
方法一:不建议使用
设置create_date、modify_date的默认值为CURRENT_TIMESTA-MP
方法二:使用mybatis-plus带的注解@TableField

 // 创建时间,希望在添加数据的时候填充:当前时间    @TableField(value = "create_date",fill = FieldFill.INSERT)    private Date createDate;    // 修改时间:希望在修改数据和添加数据的时候填充    @TableField(value = "modify_date",fill = FieldFill.INSERT_UPDATE)    private Date modifyDate;

添加一个配置类MyMetaObjectHandler用于设置填充的时间

@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler {    @Override    public void insertFill(MetaObject metaObject) { // 插入时:创建时间和修改时间 this.setFieldValByName("createDate",new Date(),metaObject); this.setFieldValByName("modifyDate",new Date(),metaObject);    }    @Override    public void updateFill(MetaObject metaObject) { this.setFieldValByName("modifyDate",new Date(),metaObject);    }}

七:MyBatis-Plus执行SQL分析打印

SQL分析打印:可以查看SQL的执行时间,最大的好处时显示除mybatis执行的sql的具体语句
样例:

2022-04-16 18:31:17.425 DEBUG 22096 --- [    main] c.e.q.mapper.EmployeeMapper.update: ==> Parameters: black(String), 2055(String), 1(Integer), 98(Integer), 2022-04-16 18:31:16.959(Timestamp), 10(Integer) Consume Time:351 ms 2022-04-16 18:31:17 Execute SQLUPDATE tbl_employee SET last_name='black', email='2055', gender=1, age=98, modify_date='2022-04-16T18:31:16.959+0800' WHERE enabled=1 AND (id = 10)

第一步:添加依赖

<dependency>     <groupId>p6spy</groupId>     <artifactId>p6spy</artifactId>     <version>3.9.1</version> </dependency>

第二步:更改yaml中的配置
将url和driver-class-name更改

spring:  datasource:    url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC    username: root    password: root    driver-class-name: com.p6spy.engine.spy.P6SpyDriver    type: com.alibaba.druid.pool.DruidDataSource

第三步:添加一个spy.properties文件

#3.2.1以上使用modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory#3.2.1以下使用或者不配置#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory# 自定义日志打印logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger#日志输出到控制台appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger# 使用日志系统记录 sql#appender=com.p6spy.engine.spy.appender.Slf4JLogger# 设置 p6spy driver 代理deregisterdrivers=true# 取消JDBC URL前缀useprefix=true# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.excludecategories=info,debug,result,commit,resultset# 日期格式dateformat=yyyy-MM-dd HH:mm:ss# 实际驱动可多个#driverlist=org.h2.Driver# 是否开启慢SQL记录outagedetection=true# 慢SQL记录标准 2 秒outagedetectioninterval=2
注意!driver-class-name 为 p6spy 提供的驱动类url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址打印出 sql 为 null,在 excludecategories 增加 commit批量操作不打印 sql,去除 excludecategories 中的 batch批量操作打印重复的问题请使用 MybatisPlusLogFactory (3.2.1 新增)该插件有性能损耗,不建议生产环境使用。

八:MyBatis-Plus乐观锁

第一:什么是乐观锁 悲观锁:
悲观锁,正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事 务,以及来自外部系统的事务处理)修改持保守态度。因此,在整个数据处理过程中,将数据处于锁定状态。 假设功能并发量非常大,就需要使用synchronized来处理高并发下产生线程不安全问题, 会使其他线程进行挂起等待从 而影响系统吞吐量 。
乐观锁:乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正 式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场 景,这样可以提高程序的吞吐量。 假设功能产生并发几率极少,采用乐观锁版本机制对比, 如果有冲突 返回给用户错 误的信息

1.mybatis的配置

@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());    return interceptor;}

2在实体类的字段上加上@Version注解

@Versionprivate Integer version;

样例:

    @Test    public void testCAS(){ // 线程1 age50 version1 Employee employee1 = employeeService.getById(1); // 线程2 age50 version 1 Employee employee2 = employeeService.getById(1); employee1.setAge(100); employee2.setAge(50); System.out.println(employeeService.updateById(employee1)); System.out.println(employeeService.updateById(employee2));    }

九:MyBatis-Plus分页

直接在启动类中增加就可

@Configuration@MapperScan("scan.your.mapper.package")public class MybatisPlusConfig {    /**     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)     */    @Bean    public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor;    }    @Bean    public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false);    }}

xml文件配置

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.quickstart.mapper.EmployeeMapper">    <select id="getByGender" resultType="com.example.quickstart.pojo.Employee"> SELECT  * FROM  tbl_employee    </select>    <select id="selectAll" resultType="com.example.quickstart.pojo.Employee"> SELECT  * FROM tbl_employee    </select></mapper>

mapper层(持久层)

/** * 基于Mybatis‐plus实现: 让XxxMapper接口继承 BaseMapper接口即可. * BaseMapper : 泛型指定的就是当前Mapper接口所操作的实体类类型 */@Repositorypublic interface EmployeeMapper extends BaseMapper<Employee> {    IPage<Employee> getByGender(IPage page);    List<Employee> selectAll();}

样例测试

    @Test    public void xmlPage(){ IPage<Employee> iPage = new Page<>(5,1); IPage<Employee> page = employeeMapper.getByGender(iPage); System.out.println(page.getSize()); List<Employee> records = page.getRecords(); System.out.println(page.getPages()); System.out.println(records);    }

测试:

    @Test    public void page(){ IPage<Employee> iPage = new Page<>(1,3); IPage<Employee> page = employeeImplService.page(iPage); List<Employee> records = page.getRecords(); for (Employee record: records){     System.out.println(record); } System.out.println(page.getPages());    }