Mybatis-Plus

Mybatis-Plus的概念

MyBatis-Plus (opens new window) (简称 MP )是⼀个 MyBatis (opens new window) 的增强⼯具,在 MyBatis
的基础上只做增强不做改变,为简化开发、提⾼效率⽽⽣。

特性

⽆侵⼊:只做增强不做改变,引⼊它不会对现有⼯程产⽣影响,如丝般顺滑。
损耗⼩:启动即会⾃动注⼊基本 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 操作智能分析阻断,也可⾃定义拦截规则,预防误操作。

快速入门

引⼊依赖

 <dependency>
 <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>最新版本</version>
</dependency>

配置数据源

application.yml 配置⽂件中添加 MySQL 数据库的相关配置:
# DataSource Config
spring:
 datasource:
 driver-class-name: com.mysql.cj.jdbc.Driver
 url: jdbc:mysql://localhost:3306/test
 type: com.alibaba.druid.pool.DruidDataSource
 username: root
 password: 1234

实体类

 我们以经典的 Emp 表作为实例,进⾏讲解,编写对应的实体 Emp 类。

@Data
public class Emp implements Serializable {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private String hiredate;
private Double sal;
private Double comm;
private Integer deptno;
private Integer empstate;
}

Mapper

编写 mapper 包下的 EmpMapper 接⼝
@Mapper
public interface EmpMapper extends BaseMapper<Emp>{
}

业务层

编写 service 包下的 EmpService 接⼝

public interface EmpService extends IService<Emp>{
}
编写 service.impl 包下的 EmpServiceImpl 实现类
@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService {
}

开始使⽤

添加测试类,进⾏功能测试

@SpringBootTest
public class SampleTest {
@Resource
private EmpService empService;
@Test
void findTest() {
List<Emp> list = empService.list();
list.forEach(System.out::println);
 }
}
通过以上⼏个简单的步骤,我们就实现了 Emp 表的 CRUD 功能,甚⾄连 XML ⽂件都不⽤编写!
从以上步骤中,我们可以看到集成 MyBatis-Plus ⾮常的简单,只需要引⼊ starter ⼯程,并配置 mapper 扫描路径
即可。
MyBatis-Plus 的强⼤远不⽌这些功能,想要详细了解 MyBatis-Plus 的强⼤功能?那就继续往下看吧!

MyBatis-Plus 注解

@TableName

描述:表名注解,标识实体类对应的表
使⽤位置:实体类
@Data
@TableName(value = "emp")
public class Emp implements Serializable {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private String hiredate;
private Double sal;
private Double comm;
private Integer deptno;
private Integer empstate;
}
注意 @TableName 注解可省略,如省略对应类名的表
属性列表:

 关于 autoResultMap 的说明:

MP 会⾃动构建⼀个 resultMap 并注⼊到 MyBatis ⾥(⼀般⽤不上),请注意以下内容:
因为 MP 底层是 MyBatis ,所以 MP 只是帮您注⼊了常⽤ CRUD MyBatis ⾥,注⼊之前是动态的(根据您的 Entity 字段以及注解变化⽽变化),但是注⼊之后是静态的(等于 XML 配置中的内容)。
⽽对于 typeHandler 属性, MyBatis 只⽀持写在 2 个地⽅ :
1. 定义在 resultMap ⾥,作⽤于查询结果的封装
2. 定义在 insert update 语句的 #{property} 中的 property 后⾯(例: #
{property,typehandler=xxx.xxx.xxx} ),并且只作⽤于当前 设置值。
除了以上两种直接指定 typeHandler 的形式, MyBatis 有⼀个全局扫描⾃定义 typeHandler 包的配置,原理是
根据您的 property 类型去找其对应的 typeHandler 并使⽤。

@TableId

描述:主键注解
使⽤位置:实体类主键字段
@Data
@TableName(value = "emp")
public class Emp implements Serializable {
@TableId(value = "empno",type = IdType.AUTO)
private Integer empno;
// 其他省略
}
属性列表
type 属性概述:

 @TableField

描述:字段注解(⾮主键)

@Data
@TableName(value = "emp")
public class Emp implements Serializable {
@TableField(value = "ename")
private String ename;
@TableField(value = "hiredate")
private String hireDate;
// 其他省略
}
属性列表:
关于 jdbcType typeHandler 以及 numericScale 的说明 :
numericScale 只⽣效于 update sql. jdbcType typeHandler 如果不配合 @TableName#autoResultMap = true⼀起使⽤ , 也只⽣效于 update sql. 对于 typeHandler 如果你的字段类型和 set 进去的类型为 equals 关系, 则只需要让你的 typeHandler Mybatis 加载到即可 , 不需要使⽤注解。

 @TableLogic

描述:表字段逻辑处理注解(逻辑删除)

 逻辑删除

我们在实际使⽤中的删除操作,其实并没有删除表中的数据,仅仅是将表的数据 隐藏 掉,查询时不查询这些 隐藏的数据。

全局⽅式 

application.yml 中进⾏配置: 

mybatis-plus:
 global-config:
 db-config:
 logic-delete-field: state # 全局逻辑删除的实体字段名
 logic-delete-value: 0 # 逻辑已删除值(默认为 1)
 logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)

 注意:配置好后,所有实体不需额外操作,但必须保证存在 state 字段

局部⽅式 

需要在每个所需实体类中引⼊ @TableLogic 注解。 

package com.jiazhong.bean;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.io.Serializable;

@Data
@TableName(value = "emp")  //  对应的数据库的名称
public class Emp implements Serializable {
    // 主键对应  AUTO:自增
    @TableId(value = "empno", type = IdType.AUTO)
    private Integer empNo; // 默认情况下对应数据库表中的名称为:emp_no
    @TableField(value = "ename")  //  自动映射数据库表中的列名为ename
    private String ename;
    private String job;
    private Integer mgr;
    @TableField(value = "hiredate",fill = FieldFill.INSERT)
    private String hireDate;  //  当save时自动填充内容
    private Double sal;
    private Double comm;
    @TableField("deptno")
    private Integer deptNo;
    @TableLogic(delval = "0",value = "1")   //  非全局控制逻辑删除
    private Integer state;


    //  这个列在数据库中不存在
    @TableField(exist = false)
    private String allCount;
}

 说明

只对⾃动注⼊的 sql 起效:
插⼊ : 不作限制
查找 : 追加 where 条件过滤掉已删除数据 , 如果使⽤ wrapper.entity ⽣成的 where 条件也会⾃动追加该字段.
更新 : 追加 where 条件防⽌更新到已删除数据 , 如果使⽤ wrapper.entity ⽣成的 where 条件也会⾃动追加该字段
删除 : 转变为 更新
例如 :
删除 : update user set deleted=1 where id = 1 and deleted=0
查找 : select id,name,deleted from user where deleted=0
字段类型⽀持说明:
⽀持所有数据类型 ( 推荐使⽤ Integer,Boolean,LocalDateTime)
如果数据库字段使⽤ datetime , 逻辑未删除值和已删除值⽀持配置为字符串 null, 另⼀个值⽀持配置为函数来获取值如now()
逻辑删除是为了⽅便数据恢复和保护数据本身价值等等的⼀种⽅案,但实际就是删除。
如果你需要频繁查出来看就不应使⽤逻辑删除,⽽是以⼀个状态去表示。

 ⾃动填充功能

在数据表的设计中,经常需要加⼀些字段,如:创建时间,最后修改时间等,此时可以使⽤ MyBatis-Plus 来帮我 们进⾏⾃动维护。

⾃动填充⽅式有两种,分别是:

通过数据库完成⾃动填充
使⽤程序完成⾃动填充

数据库⾃动填充 

这⾥没什么好说的,就是正常书写就⾏,在添加时,有默认值的列所对应的属性不赋值,数据库会⾃动赋予默认值.

 程序⾃动填充

Emp.java

package com.jiazhong.bean;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.io.Serializable;

@Data
@TableName(value = "emp")  //  对应的数据库的名称
public class Emp implements Serializable {
    // 主键对应  AUTO:自增
    @TableId(value = "empno", type = IdType.AUTO)
    private Integer empNo; // 默认情况下对应数据库表中的名称为:emp_no
    @TableField(value = "ename")  //  自动映射数据库表中的列名为ename
    private String ename;
    private String job;
    private Integer mgr;
    @TableField(value = "hiredate",fill = FieldFill.INSERT)
    private String hireDate;  //  当save时自动填充内容
    private Double sal;
    private Double comm;
    @TableField("deptno")
    private Integer deptNo;
    @TableLogic(delval = "0",value = "1")   //  非全局控制逻辑删除
    private Integer state;


    //  这个列在数据库中不存在
    @TableField(exist = false)
    private String allCount;
}
创建util类,在创建 NowDateHandler.java
package com.jiazhong.util;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class NowDateHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "hireDate", this::getNowDate, String.class);
    }

    @Override
    public void updateFill(MetaObject metaObject) {

    }

    private String getNowDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(new Date());
    }
}

当使用save()方法时,会自动的将hiredate设为现在的时间。

 @Test
    public void d() {
        Emp emp = new Emp();
        emp.setComm(980.0);j
        emp.setSal(9876.0);
        emp.setJob("程序员");
        emp.setEname("火鳞飞");
        emp.setMgr(8787);
        emp.setDeptNo(10);
        emp.setState(1);
        boolean b = service.save(emp);
        System.out.println(b);
    }

而在 NowDateHandler.java 文件中还有一个  updateFill()方法,则对应的是update()方法。

说明 

填充原理是直接给 entity 的属性设置值 !!!
注解则是指定该属性在对应情况下必有值 , 如果⽆值则⼊库会是 null
MetaObjectHandler 提供的默认⽅法的策略均为 : 如果属性有值则不覆盖 , 如果填充值为 null 则不填充
字段必须声明 TableField 注解 , 属性 fill 选择对应策略 , 该声明告知 Mybatis-Plus 需要预留注⼊ SQL 字段
填充处理器 NowDateHandler Spring Boot 中需要声明 @Component @Bean 注⼊
要想根据注解 FieldFill.xxx 和字段名以及字段类型来区分必须使⽤⽗类的 strictInsertFill 或者
strictUpdateFill ⽅法
不需要根据任何来区分可以使⽤⽗类的 fillStrategy ⽅法
update(T t,Wrapper updateWrapper) t 不能为空 , 否则⾃动填充失效

条件构造器

Mybatis-Plus 中提了构造条件的类 Wrapper , 它可以根据⾃⼰的意图定义我们需要的条件。 Wrapper 是⼀个抽象
类,⼀般情况下我们⽤它的⼦类 QueryWrapper 来实现⾃定义条件查询。

 

API 

Test.java

package com.jiazhong.test;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.jiazhong.bean.Emp;
import com.jiazhong.mapper.EmpMapper;
import com.jiazhong.service.EmpService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@SpringBootTest
public class a {
    @Resource
    private EmpService service;

    @Test
    public void f1() {
        // 按照职位进行检索
        // 书写条件构造器
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        // 设置条件  eq ne lt le gt ge
        wrapper.eq("job", "程序员");
        // 查询
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void f2() {
        //   按照职位进行探索
        //   书写条件构造器
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        //  设置条件  eq ne lt le gt ge
//        wrapper.eq("job", "程序员");
        //  查询  and
        wrapper.ge("sal", 3000);
        wrapper.le("sal", 5000);
//        wrapper.between("sal", 3000, 5000);
        // 查询
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void f3() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        wrapper.like("ename", "三");
//        wrapper.likeLeft("ename","三");
//        wrapper.likeRight("ename","三");
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void f4() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
//        wrapper.notIn("job", "歌手", "程序员", "页面设计");
        wrapper.in("job", "歌手", "程序员", "页面设计");
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void f5() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        wrapper.eq("job", "程序员")
                .or()
                .eq("job", "页面设计")
                .or()
                .eq("job", "歌手");
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void f6() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
//        wrapper.orderByAsc("sal");
//        wrapper.orderByDesc("comm");  //  两者之间为and关系
        wrapper.orderByDesc("sal", "comm");  // 两者效果一样
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void f7() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        //  查询哪些列
        wrapper.select("sal", "job");
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void f8() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        wrapper.select("count(*)", "sum(sal)", "avg(sal)", "max(sal)", "min(sal)");
        // 查询
        List<Map<String, Object>> maps = service.listMaps(wrapper);  //  键值对形式封装
        System.out.println(maps);
    }

    @Test
    public void f9() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        wrapper.groupBy("job");
        wrapper.select("job", "count(*) as allCoount");
        // 查询
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }


    @Test
    public void f10() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        wrapper.groupBy("job");
        wrapper.select("job", "count(*) as alLCount");
        wrapper.gt("sal", 3000);
        wrapper.gt("sal", 1000);
        wrapper.having("allCount>3");
        // 查询
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void f11() {
        QueryWrapper<Emp> wrapper = new QueryWrapper<>();
        //  拼接到sql语句之后
        wrapper.last("and sal>1000");
        // 查询
        List<Emp> list = service.list(wrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void g() {
        UpdateWrapper<Emp> wrapper = new UpdateWrapper<>();
        wrapper.set("job", "歌手");
        wrapper.eq("empno", "7369");
        service.update(wrapper);
    }

    @Test
    public void h() {
        EmpMapper mapper = (EmpMapper) service.getBaseMapper();
        List<Emp> emp = mapper.findEmp();
        emp.forEach(System.out::println);
    }
}

 AbstractWrapper

说明 :
QueryWrapper(LambdaQueryWrapper) UpdateWrapper(LambdaUpdateWrapper) 的⽗类
⽤于⽣成 sql where 条件 , entity 属性也⽤于⽣成 sql where 条件
注意 : entity ⽣成的 where 条件与 使⽤各个 api ⽣成的 where 条件 没有任何关联⾏为
QueryWrapper
select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
设置查询字段
说明 :
以上⽅法分为两类 .
第⼆类⽅法为 : 过滤查询字段 ( 主键除外 ), ⼊参不包含 class 的调⽤前需要 wrapper 内的 entity 属性有值 !
这两类⽅法重复调⽤以最后⼀次为准
: select("id", "name", "age")
: select(i -> i.getProperty().startsWith("test"))
UpdateWrapper
说明 :
继承⾃ AbstractWrapper , ⾃身的内部属性 entity 也⽤于⽣成 where 条件
LambdaUpdateWrapper , 可以通过 new UpdateWrapper().lambda() ⽅法获取 !

set

set ( String column , Object val )
set ( boolean condition , String column , Object val )
SQL SET 字段
: set("name", " ⽼李头 ")
: set("name", "") ---> 数据库字段值变为 空字符串
: set("name", null) ---> 数据库字段值变为 null

使⽤ XML 配置(结合Mybatis使用)

有的时候对于⼀些复杂 SQL 语句,尤其是动态SQL,使⽤注解⽐较麻烦,我们可以通过 XML 来书写。 

application.yml 引⼊ 

mybatis-plus:
  mapper-locations: classpath*:/mapper/EmpMapper.xml # mapper ⽂件位置

 根据接⼝⽣成xml配置⽂件

所对应的EmpMapper.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.jiazhong.mapper.EmpMapper">
    <select id="findEmp" resultType="com.jiazhong.bean.Emp">
        select *
        from emp
        where state = 1
    </select>
</mapper>

Test.java

@SpringBootTest
public class a {
    @Resource
    private EmpService service;

    @Test
    public void h() {
        EmpMapper mapper = (EmpMapper) service.getBaseMapper();
        List<Emp> emp = mapper.findEmp();
        emp.forEach(System.out::println);
    }
}

  • 21
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值