MyBatis-Plus 学习笔记

MyBatis-Plus官网地址:https://mp.baomidou.com/

一、mybatis-plus简介:

Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。

二、mybatis-plus特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

三、MyBatis-Plus VS JPA

MyBatis-Plus优势:

  • SQL语句可以自由控制,更灵活,性能较高
  • SQL于代码分离,易于阅读和维护
  • 提供XML标签,支持编写动态SQL语句

JPA优势:

  • JPA移植性比较好
  • 提供了很多 CRUD方法、开发效率高
  • 对象化程度更高

MyBatis-Plus劣势:

  • 简单的CURD都要写SQL
  • XML中有大量的SQL要维护
  • MyBatis自身功能很有限,但支持PLlugin

四、常用注解

  • @TableName:对数据表名注解
  • @TableId:表主键标识
  • @TableId(value = “id”, type = IdType.AUTO):自增
  • @TableId(value = “id”, type = IdType.ID_WORKER_STR):分布式全局唯一ID字符串类型
  • @TableId(value = “id”, type = IdType.INPUT):自行输入
  • @TableId(value = “id”, type = IdType.ID_WORKER):分布式全局唯一ID 长整型类型
  • @TableId(value = “id”, type = IdType.UUID):32位UUID字符串
  • @TableId(value = “id”, type = IdType.NONE):无状态
  • @TableField:表字段标识
  • @TableField(exist = false):表示该属性不为数据库表字段,但又是必须使用的。
  • @TableField(exist = true):表示该属性为数据库表字段。
  • @TableField(condition = SqlCondition.LIKE):表示该属性可以模糊搜索。
  • @TableField(fill = FieldFill.INSERT):注解填充字段 ,生成器策略部分也可以配置!
  • @Version:乐观锁注解、标记
  • @EnumValue:通枚举类注解
  • @TableLogic:表字段逻辑处理注解(逻辑删除)
  • @SqlParser:租户注解
  • @KeySequence:序列主键策略

五、普通查询

增:

    @Autowired
    private RentDetailMapper rentDetailMapper;

    @Override
    public void insert(String userId, String dealerId, String strategyId) {
        RentDetail rentDetail=new RentDetail();
        //插入
        rentDetail.setUserId(userId);
        rentDetail.setDealerId(dealerId);
        rentDetail.setStrategyId(strategyId);
        rentDetailMapper.insert(rentDetail);
    }

删:

    @Autowired
    private RentDetailMapper rentDetailMapper;

    @Override
    public void delete(String Id) {
        //删除
        rentDetailMapper.deleteById(Id);
    }

改:

    @Autowired
    private RentDetailMapper rentDetailMapper;

    @Override
    public void update(String userId, String dealerId, String strategyId) {
        RentDetail rentDetail=new RentDetail();
        //更新
        rentDetail.setUserId(userId);
        rentDetail.setDealerId(dealerId);
        rentDetail.setStrategyId(strategyId);
        rentDetailMapper.updateById(rentDetail);
    }

查:

    @Autowired
    private RentDetailMapper rentDetailMapper;

    @Override
    public void select(String Id) {
        //查找
        rentDetailMapper.selectById(Id);
    }

六、自定义SQL查询

接口示例:

@Mapper
@Repository
public interface IUserDao extends BaseMapper<User> {

    /**
     * 根据电话查找id、昵称
     * @param mobile
     * @param sourceId
     * @return
     */
    List<UserMobileVO> findId(@Param("mobile")String mobile,@Param("sourceId")String sourceId);
}

xml示例:
ps:MyBatisPlus是有驼峰命名的,不需要一个一个字段进行映射

<?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.netx.web.dao.IUserDao">

    <select id="findId" resultType="com.netx.web.vo.UserMobileVO" >
   SELECT
    id,
    mobile,
    real_name
    FROM
        `user`
    WHERE
        mobile like '%${mobile}%'and
        deleted = 0
        and register_source=#{sourceId}
    </select>
</mapper>

动态SQL示例:
PS:若是排序的动态查询需要注意不用#{字段名}而是用${字段名}

<select id="pageStrategy" resultType="com.app.entity.Strategy">
        select * from strategy
        <where>
             <!--若传入的参数为空,则不做对应的筛选-->
            <if test="search.house != null and search.house != ''">
                house = #{search.house}
            </if>
            <if test="search.currncy != null and search.currncy != ''">
                and currncy = #{search.currncy}
            </if>
            and deleted = 0 order by
        <choose>
             <!--若某一参数不为空,则做对应的排序(这里要前端传desc或asc来做降升序控制)-->
            <when test="search.yiedlRate != null and search.yiedlRate != ''">
                yiedl_rate ${search.yiedlRate}
            </when>
            <when test="search.winRate != null and search.winRate != ''">
                win_rate ${search.winRate}
            </when>
            <when test="search.totalRentedCount != null and search.totalRentedCount != ''">
                total_rented_count ${search.totalRentedCount}
            </when>
            <otherwise>
                create_time desc
            </otherwise>
        </choose>
        </where>
    </select>

七、条件构造器

更多详细用法尽在官方文档:https://mp.baomidou.com/guide/wrapper.html#select

查:

    /**
     * 条件构造器 查询操作
     * 年龄在 18~50 之间性别为男且姓名为 xx 的所有用户
     *SELECT id AS id,last_name AS lastName,email,gender,age FROM tbl_employee WHERE (age BETWEEN ? AND ? AND gender = ? AND last_name = ?)
     */

    @Test
    public void testSelectPage(){
        Page<Employee> page=new Page<>(0,2);
        EntityWrapper<Employee> entityWrapper=new EntityWrapper<>();
        entityWrapper.between("age",18,50).eq("gender",1).eq("last_name","Tom");
        List<Employee> list = employeeMapper.selectPage(page, entityWrapper);
        System.out.println(list);
    }

删:

     /**
     * 条件构造器 删除操作
     *删除名字为Tom并且性别为女年龄为45
     *DELETE FROM tbl_employee WHERE (last_name = ? AND gender = ? AND age = ?)
     */
    @Test
    public void testDelete(){
        EntityWrapper<Employee> entityWrapper=new EntityWrapper<>();
        entityWrapper.eq("last_name","Tom").eq("gender",0).eq("age",45);
        Integer row = employeeMapper.delete(entityWrapper);
        System.out.println(row);
    }

改:

      /**
     * 条件构造器 修改操作
     *名字为xiaohong并且性别为女年龄为10的人名字改为honghonglaoshi,邮箱改为120@qq.com
     * UPDATE tbl_employee SET last_name=?, email=? WHERE (last_name = ? AND gender = ? AND age = ?)
     */
    @Test
    public void testUpdate(){
        Employee employee=new Employee();
        employee.setLastName("honghonglaoshi");
        employee.setEmail("120@qq.com");
        EntityWrapper<Employee> entityWrapper=new EntityWrapper<>();
        entityWrapper.eq("last_name","xiaohong").eq("gender",0).eq("age",10);
        Integer row = employeeMapper.update(employee, entityWrapper);
        System.out.println(row);
    }

八、分页查询

官方文档:https://mybatis.plus/guide/page.html

XML 自定义分页

public interface UserMapper {//可以继承或者不继承BaseMapper
    /**
     * <p>
     * 查询 : 根据state状态查询用户列表,分页显示
     * </p>
     *
     * @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位(你可以继承Page实现自己的分页对象)
     * @param state 状态
     * @return 分页对象
     */
    IPage<User> selectPageVo(Page<?> page, Integer state);
}
  • UserMapper.xml 等同于编写一个普通 list 查询,mybatis-plus 自动替你分页
<select id="selectPageVo" resultType="com.baomidou.cloud.entity.UserVo">
    SELECT id,name FROM user WHERE state=#{state}
</select>
  • UserServiceImpl.java 调用分页方法
public IPage<User> selectUserPage(Page<User> page, Integer state) {
    // 不进行 count sql 优化,解决 MP 无法自动优化 SQL 问题,这时候你需要自己查询 count 部分
    // page.setOptimizeCountSql(false);
    // 当 total 为小于 0 或者设置 setSearchCount(false) 分页插件不会进行 count 查询
    // 要点!! 分页返回的对象与传入的对象是同一个
    return userMapper.selectPageVo(page, state);
}

九、AR策略 (Active Record活动记录)

  • Active Record(活动记录),简称AR,是一种领域模型模式,特点就是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一条记录;
    参考文章:https://blog.csdn.net/xiaofeivip_top/article/details/94871238
    开启AR模式的方法很简单,就是让我们的实体类继承Model类,并实现其抽象方法,指定主键即可,如下:
@Data
public class Employee extends Model<Employee> {

   @TableId(value = "id",type = IdType.AUTO)
   private Integer id;

   @TableField
   private String lastName;
   private String email;
   private Integer gender;
   private Integer age;

   /**
    * 通过exit设置当前字段不存在数据库里面
    */
   @TableField(exist = false)
   private Double salary;

   /**
    * 指定当前实体类的 主键属性
    * @return
    */
   @Override
   protected Serializable pkVal() {
       return id;
   }

}

测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootMybatisplusARTests {

    /**
     * 添加
     */
    @Test
    public void insertAR() {
        Employee employee = new Employee();
        employee.setLastName("AR");
        employee.setEmail("ar@xiaofei.com");
        employee.setGender(1);
        employee.setAge(22);

        boolean insert = employee.insert();
        System.err.println(insert);
        System.err.println(employee.getId());
    }

    /**
     * 修改
     */
    @Test
    public void updateAR() {
        Employee employee = new Employee();
        employee.setId(10);
        employee.setGender(0);
        employee.setAge(0);
        boolean b = employee.updateById();
        System.err.println(b);
    }

    /**
     * 查询
     */
    @Test
    public void selectAR() {
        // 根据Id查询
        Employee employee = new Employee();
        Employee employee1 = employee.selectById(1);
        // System.err.println(employee1);

        // 查询全部
        List<Employee> employeesAll = employee.selectAll();
        // System.err.println(employeesAll);

        // 查询名字带有M的
        List<Employee> employees = employee.selectList(new EntityWrapper().like("last_name", "M"));
        // System.err.println(employees);

        // 查询总数量
        int count = employee.selectCount(null);
        // System.err.println(count);

        // 分页
        Page<Employee> page = employee.selectPage(
                new Page<Employee>(1, 2), null);
        System.err.println(page);
        /**
         *  Page:{ [Pagination { total=0 ,size=2 ,pages=0 ,current=1 }], records-size:2 }
         */
        List<Employee> emps = page.getRecords();
        System.err.println("数据:" + emps);
    }

    /**
     * 删除
     * <p>
     * 注意:删除不存在的数据在逻辑上也是成功的;
     */
    @Test
    public void deleteAR() {
        Employee employee = new Employee();
        boolean b = employee.deleteById(10);
        System.err.println(b);
    }
}

注意点:删除不存在的数据在逻辑上也是成功的;

十、基本配置

官方文档:https://mp.baomidou.com/config/#基本配置
使用方式:
Spring Boot:

mybatis-plus:
  ......
  configuration:
    ......
  global-config:
    ......
    db-config:
      ......  

Configuration

mapUnderscoreToCamelCase

  • 类型:boolean
  • 默认值:true

是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射。

​注意
​此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中,此属性也将用于生成最终的 SQL 的 select body
​如果您的数据库命名符合规则无需使用 @TableField 注解指定数据库字段名

#defaultEnumTypeHandler

  • 类型:Class<? extends TypeHandler
  • 默认值:org.apache.ibatis.type.EnumTypeHandler

默认枚举处理类,如果配置了该属性,枚举将统一使用指定处理器进行处理

  • org.apache.ibatis.type.EnumTypeHandler : 存储枚举的名称
  • org.apache.ibatis.type.EnumOrdinalTypeHandler : 存储枚举的索引
  • com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler : 枚举类需要实现IEnum接口或字段标记@EnumValue注解.(3.1.2以下版本为EnumTypeHandler)

其他就不一一列举,有兴趣可以在官方文档查阅

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容