• mybatis学习笔记——mybatis-plus快速入门


    一、快速入门

    MyBatis-plus (简称mp)是一款 Mybatis 增强工具,用来简化开发、增强效率。本文结合Spring Boot来实现mp的快速入门。
    注:本文演示mp版本为当前最新的3.5.1
    官方网站:https://baomidou.com/

    1、创建SpringBoot项目
    2、导入依赖

    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.7.2version>
            <relativePath/> 
        parent>
        <groupId>com.examplegroupId>
        <artifactId>mybatis-plus-demoartifactId>
        <version>0.0.1-SNAPSHOTversion>
        <name>mybatis-plus-demoname>
        <description>Demo project for Spring Bootdescription>
        <properties>
            <java.version>1.8java.version>
        properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starterartifactId>
            dependency>
    
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-configuration-processorartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-boot-starterartifactId>
                <version>3.5.1version>
            dependency>
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>5.1.20version>
                <scope>runtimescope>
            dependency>
            
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.12version>
                <scope>testscope>
            dependency>
    
        dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombokgroupId>
                                <artifactId>lombokartifactId>
                            exclude>
                        excludes>
                    configuration>
                plugin>
            plugins>
        build>
    
    project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    3、配置
    application.yml配置文件

    spring:
      datasource:
      	#mysql驱动6.0版本以上的为com.mysql.cj.jdbc.Driver
        driver-class-name: com.mysql.jdbc.Driver	
        url: jdbc:mysql://localhost:3306/test
        username: root
        password: root1234
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、数据库脚本

    DROP TABLE IF EXISTS user;
    
    CREATE TABLE user
    (
        id BIGINT(20) NOT NULL COMMENT '主键ID',
        name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
        age INT(11) NULL DEFAULT NULL COMMENT '年龄',
        email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
        PRIMARY KEY (id)
    );
    
    DELETE FROM user;
    
    INSERT INTO user (id, name, age, email) VALUES
    (1, 'Jone', 18, 'test1@baomidou.com'),
    (2, 'Jack', 20, 'test2@baomidou.com'),
    (3, 'Tom', 28, 'test3@baomidou.com'),
    (4, 'Sandy', 21, 'test4@baomidou.com'),
    (5, 'Billie', 24, 'test5@baomidou.com');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    5、编码
    实体类:

    package com.example.demo.po;
    
    import lombok.Data;
    
    /**
     * 〈实体类,类名和属性名需要符合驼峰命名法,可以不用关联表名,mybatis会自动关联〉
    * 否则需要使用mybatis的@TableName,@TableId,@TableField等注解,将实体类和表关联 */
    @Data public class User { private Long id; private String name; private Integer age; private String email; }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    mapper接口:

    package com.example.demo.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.example.demo.po.User;
    
    public interface UserMapper extends BaseMapper<User> {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    service接口

    package com.example.demo.service;
    
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.example.demo.po.User;
    
    public interface UserService extends IService<User> {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    service实现类:

    package com.example.demo.service.impl;
    
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.example.demo.mapper.UserMapper;
    import com.example.demo.po.User;
    import com.example.demo.service.UserService;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Spring Boot 启动类:

    package com.example.mybatisplusdemo;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication(scanBasePackages = "com.example")
    @MapperScan("com.example.demo.mapper")
    public class MybatisPlusDemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MybatisPlusDemoApplication.class, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试类

    package com.example.mybatisplusdemo;
    
    import com.example.demo.mapper.UserMapper;
    import com.example.demo.po.User;
    import com.example.demo.service.UserService;
    import org.junit.jupiter.api.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.List;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    class MybatisPlusDemoApplicationTests {
    
        @Autowired
        private UserMapper userMapper;
        @Autowired
        private UserService userService;
    
        @Test
        void contextLoads() {
    
            List<User> userList = userMapper.selectList(null);
            userList.forEach(System.out::println);
        }
        @Test
        void test(){
            List<User> userList = userService.getBaseMapper().selectList(null);
            userList.forEach(System.out::println);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    运行测试方法结果:
    在这里插入图片描述
    项目结构:
    在这里插入图片描述
    mp的service里定义了mapper,我们在service里使用mapper时无需注入,直接使用this.baseMapper即可。

    二、核心功能

    1、注解

    @TableName

    表名注解,标识实体类对应的表。如果类名使用驼峰命名法命名,可以不使用该注解。示例:ta_user表对应的实体类为taUser。或者表名与类名相同也无需使用该注解

    属性类型必须指定默认值描述
    valueString""表名
    schemaString""schema
    keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
    resultMapString""xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
    autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
    excludePropertyString[]{}需要排除的属性名 @since 3.3.1

    @TableId

    主键注解,用在主键字段上

    属性类型必须指定默认值描述
    valueString""主键字段名
    typeEnumIdType.NONE指定主键类型

    IdType的值

    描述
    AUTO数据库 ID 自增
    NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
    INPUTinsert 前自行 set 主键值
    ASSIGN_ID分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
    ASSIGN_UUID分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)
    ID_WORKER分布式全局唯一 ID 长整型类型(please use ASSIGN_ID)
    UUID32 位 UUID 字符串(please use ASSIGN_UUID)
    ID_WORKER_STR分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

    @TableField

    字段注解(非主键)

    属性类型必须指定默认值描述
    valueString""数据库字段名
    existbooleantrue是否为数据库表字段
    conditionString""字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s}参考 (opens new window)
    updateString""字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)
    insertStrategyEnumFieldStrategy.DEFAULT举例:NOT_NULL
    insert into table_a(column) values (#{columnProperty})
    updateStrategyEnumFieldStrategy.DEFAULT举例:IGNORED
    update table_a set column=#{columnProperty}
    whereStrategyEnumFieldStrategy.DEFAULT举例:NOT_EMPTY
    where column=#{columnProperty}
    fillEnumFieldFill.DEFAULT字段自动填充策略
    selectbooleantrue是否进行 select 查询
    keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
    jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC 类型 (该默认值不代表会按照该值生效)
    typeHandlerClassUnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)
    numericScaleString""指定小数点后保留的位数

    FieldStrategy
    字段验证策略

    描述
    IGNORED忽略判断
    NOT_NULL非 NULL 判断
    NOT_EMPTY非空判断(只对字符串类型字段,其他类型字段依然为非 NULL 判断)
    DEFAULT追随全局配置
    NEVER不加入SQL

    FieldFill
    字段填充策略

    描述
    DEFAULT默认不处理
    INSERT插入时填充字段
    UPDATE更新时填充字段
    INSERT_UPDATE插入和更新时填充字段

    @Version

    乐观锁注解、标记 @Verison 在字段上,作为版本号。

    @EnumValue

    普通枚举类注解(注解在枚举字段上)

    @TableLogic

    属性类型必须指定默认值描述
    valueString""逻辑未删除值
    delvalString""逻辑删除值

    @KeySequence

    序列主键策略 (oracle)

    属性类型必须指定默认值描述
    valueString""序列名
    clazzClassLong.classid 的类型, 可以指定 String.class,这样返回的 Sequence 值是字符串"1"

    @OrderBy

    内置 SQL 默认指定排序,优先级低于 wrapper 条件查询

    属性类型必须指定默认值描述
    isDescbooleantrue是否倒序查询
    sortshortShort.MAX_VALUE数字越小越靠前

    @InterceptorIgnore

    插件过滤规则

    2、CRUD接口

    mp封装了一些最基础的CRUD方法,只需要直接继承mp提供的接口,无需编写任何SQL,即可食用。mp提供了两套接口,分别是Mapper CRUD接口和Service CRUD接口。并且mp还提供了条件构造器Wrapper,可以方便地组装SQL语句中的WHERE条件。

    Mapper CRUD接口

    只需定义好实体类,然后创建一个接口,继承mp提供的BaseMapper,即可使用。mp会在mybatis启动时,自动解析实体类和表的映射关系,并注入带有通用CRUD方法的mapper。

    部分方法示例:

    insert(T entity)  插入一条记录
    
    deleteById(Serializable id)  根据主键id删除一条记录
    
    delete(Wrapper<T> wrapper) 根据条件构造器wrapper进行删除
    
    deleteByMap(Map<String, Object> columnMap) 根据多个列删除数据
    
    deleteBatchIds(Collection<?> idList) 根据主键id进行批量删除
    
    selectById(Serializable id) 根据主键id进行查找
    
    selectBatchIds(Collection idList) 根据主键id进行批量查找
    
    selectByMap(Map<String,Object> map) 根据map中指定的列名和列值进行等值匹配查找
    
    selectMaps(Wrapper<T> wrapper)  根据 wrapper 条件,查询记录,将查询结果封装为一个MapMap的key为结果的列,value为值
    
    selectList(Wrapper<T> wrapper) 根据条件构造器wrapper进行查询
    
    selectOne(Wrapper<T> queryWrapper) 根据条件查找第一条记录
    
    update(T entity, Wrapper<T> wrapper) 根据条件构造器wrapper进行更新
    
    updateById(T entity) 根据id更新记录
    
    exists(Wrapper<T> queryWrapper) 根据条件查找是否存在记录
    
    selectCount(Wrapper<T> queryWrapper) 查询行数
    
    selectPage(P page, Wrapper<T> queryWrapper) 分页查询,结果是实体类
    
    selectMapsPage(P page, Wrapper<T> queryWrapper) 分页查询,结果是map
    
    selectObjs(Wrapper<T> queryWrapper) 只查询第一列数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    Service CRUD 接口

    另外一套CRUD是Service层的,只需要编写一个接口,继承IService,并创建一个接口实现类即可使用。这个接口提供的CRUD方法,和Mapper接口提供的功能大同小异,比较明显的区别在于IService支持了更多的批量化操作,如saveBatch,saveOrUpdateBatch等方法。

    // 插入一条记录(选择字段,策略插入)
    boolean save(T entity);
    // 插入(批量)
    boolean saveBatch(Collection<T> entityList);
    // 插入(批量)
    boolean saveBatch(Collection<T> entityList, int batchSize);
    
    // TableId 注解存在更新记录,否插入一条记录
    boolean saveOrUpdate(T entity);
    // 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
    boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
    // 批量修改插入
    boolean saveOrUpdateBatch(Collection<T> entityList);
    // 批量修改插入
    boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
    
    // 根据 entity 条件,删除记录
    boolean remove(Wrapper<T> queryWrapper);
    // 根据 ID 删除
    boolean removeById(Serializable id);
    // 根据 columnMap 条件,删除记录
    boolean removeByMap(Map<String, Object> columnMap);
    // 删除(根据ID 批量删除)
    boolean removeByIds(Collection<? extends Serializable> idList);
    
    // 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
    boolean update(Wrapper<T> updateWrapper);
    // 根据 whereWrapper 条件,更新记录
    boolean update(T updateEntity, Wrapper<T> whereWrapper);
    // 根据 ID 选择修改
    boolean updateById(T entity);
    // 根据ID 批量更新
    boolean updateBatchById(Collection<T> entityList);
    // 根据ID 批量更新
    boolean updateBatchById(Collection<T> entityList, int batchSize);
    
    // 根据 ID 查询
    T getById(Serializable id);
    // 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
    T getOne(Wrapper<T> queryWrapper);
    // 根据 Wrapper,查询一条记录
    T getOne(Wrapper<T> queryWrapper, boolean throwEx);
    // 根据 Wrapper,查询一条记录
    Map<String, Object> getMap(Wrapper<T> queryWrapper);
    // 根据 Wrapper,查询一条记录
    <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
    
    // 无条件分页查询
    IPage<T> page(IPage<T> page);
    // 条件分页查询
    IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
    // 无条件分页查询
    IPage<Map<String, Object>> pageMaps(IPage<T> page);
    // 条件分页查询
    IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
    
    // 查询所有
    List<T> list();
    // 查询列表
    List<T> list(Wrapper<T> queryWrapper);
    // 查询(根据ID 批量查询)
    Collection<T> listByIds(Collection<? extends Serializable> idList);
    // 查询(根据 columnMap 条件)
    Collection<T> listByMap(Map<String, Object> columnMap);
    // 查询所有列表
    List<Map<String, Object>> listMaps();
    // 查询列表
    List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
    // 查询全部记录
    List<Object> listObjs();
    // 查询全部记录
    <V> List<V> listObjs(Function<? super Object, V> mapper);
    // 根据 Wrapper 条件,查询全部记录
    List<Object> listObjs(Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询全部记录
    <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
    
    // 查询总记录数
    int count();
    // 根据 Wrapper 条件,查询总记录数
    int count(Wrapper<T> queryWrapper);
    
    // 链式查询 普通
    QueryChainWrapper<T> query();
    // 链式查询 lambda 式。注意:不支持 Kotlin
    LambdaQueryChainWrapper<T> lambdaQuery();
    
    // 链式更改 普通
    UpdateChainWrapper<T> update();
    // 链式更改 lambda 式。注意:不支持 Kotlin
    LambdaUpdateChainWrapper<T> lambdaUpdate();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    3、条件构造器

    mp提供了强大的条件构造器Wrapper,条件构造器主要涉及到3个类,AbstractWrapper,QueryWrapper,UpdateWrapper。条件构造器也支持lambda表达式,使用LambdaQueryChainWrapper、LambdaUpdateChainWrapper。
    在AbstractWrapper中提供了非常多的方法用于构建WHERE条件,而QueryWrapper针对SELECT语句,提供了select()方法,可自定义需要查询的列,而UpdateWrapper针对UPDATE语句,提供了set()方法,用于构造set语句。

    AbstractWrapper中用于构建SQL语句中的WHERE条件的方法进行部分列举

    eq:equals,等于
    allEq:all equals,全等于
    ne:not equals,不等于
    gt:greater than ,大于 >
    ge:greater than or equals,大于等于≥
    lt:less than,小于<
    le:less than or equals,小于等于≤
    between:相当于SQL中的BETWEEN
    notBetween
    like:模糊匹配。like("name","黄"),相当于SQL的name like '%黄%'
    likeRight:模糊匹配右半边。likeRight("name","黄"),相当于SQL的name like '黄%'
    likeLeft:模糊匹配左半边。likeLeft("name","黄"),相当于SQL的name like '%黄'
    notLike:notLike("name","黄"),相当于SQL的name not like '%黄%'
    isNull
    isNotNull
    in
    and:SQL连接符AND
    or:SQL连接符OR
    apply:用于拼接SQL,该方法可用于数据库函数,并可以动态传参
    last:无视优化规则直接拼接到 sql 的最后
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    使用案例:

    // 案例先展示需要完成的SQL语句,后展示Wrapper的写法  
      
    // 1. 名字中包含佳,且年龄小于25  
    // SELECT * FROM user WHERE name like '%佳%' AND age < 25  
    QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.like("name", "佳").lt("age", 25);  
    List<User> users = userMapper.selectList(wrapper);  
    // 下面展示SQL时,仅展示WHERE条件;展示代码时, 仅展示Wrapper构建部分  
      
    // 2. 姓名为黄姓,且年龄大于等于20,小于等于40,且email字段不为空  
    // name like '黄%' AND age BETWEEN 20 AND 40 AND email is not null  
    wrapper.likeRight("name","黄").between("age", 20, 40).isNotNull("email");  
      
    // 3. 姓名为黄姓,或者年龄大于等于40,按照年龄降序排列,年龄相同则按照id升序排列  
    // name like '黄%' OR age >= 40 order by age desc, id asc  
    wrapper.likeRight("name","黄").or().ge("age",40).orderByDesc("age").orderByAsc("id");  
      
    // 4.创建日期为2021年3月22日,并且直属上级的名字为李姓  
    // date_format(create_time,'%Y-%m-%d') = '2021-03-22' AND manager_id IN (SELECT id FROM user WHERE name like '李%')  
    wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", "2021-03-22") // 建议采用{index}这种方式动态传参, 可防止SQL注入  
        .inSql("manager_id", "SELECT id FROM user WHERE name like '李%'");  
    // 上面的apply, 也可以直接使用下面这种方式做字符串拼接,但当这个日期是一个外部参数时,这种方式有SQL注入的风险  
    wrapper.apply("date_format(create_time, '%Y-%m-%d') = '2021-03-22'");  
      
    // 5. 名字为王姓,并且(年龄小于40,或者邮箱不为空)  
    // name like '王%' AND (age < 40 OR email is not null)  
    wrapper.likeRight("name", "王").and(q -> q.lt("age", 40).or().isNotNull("email"));  
      
    // 6. 名字为王姓,或者(年龄小于40并且年龄大于20并且邮箱不为空)  
    // name like '王%' OR (age < 40 AND age > 20 AND email is not null)  
    wrapper.likeRight("name", "王").or(  
        q -> q.lt("age",40)  
          .gt("age",20)  
          .isNotNull("email")  
      );  
      
    // 7. (年龄小于40或者邮箱不为空) 并且名字为王姓  
    // (age < 40 OR email is not null) AND name like '王%'  
    wrapper.nested(q -> q.lt("age", 40).or().isNotNull("email"))  
        .likeRight("name", "王");  
      
    // 8. 年龄为30,31,34,35  
    // age IN (30,31,34,35)  
    wrapper.in("age", Arrays.asList(30,31,34,35));  
    // 或  
    wrapper.inSql("age","30,31,34,35");  
      
    // 9. 年龄为30,31,34,35, 返回满足条件的第一条记录  
    // age IN (30,31,34,35) LIMIT 1  
    wrapper.in("age", Arrays.asList(30,31,34,35)).last("LIMIT 1");  
      
    // 10. 只选出id, name 列 (QueryWrapper 特有)  
    // SELECT id, name FROM user;  
    wrapper.select("id", "name");  
      
    // 11. 选出id, name, age, email, 等同于排除 manager_id 和 create_time  
    // 当列特别多, 而只需要排除个别列时, 采用上面的方式可能需要写很多个列, 可以采用重载的select方法,指定需要排除的列  
    wrapper.select(User.class, info -> {  
       String columnName = info.getColumn();  
       return !"create_time".equals(columnName) && !"manager_id".equals(columnName);  
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    Condition

    条件构造器的诸多方法中,均可以指定一个boolean类型的参数condition,用来决定该条件是否加入最后生成的WHERE语句中,比如

    String name = "黄"; // 假设name变量是一个外部传入的参数  
    QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.like(StringUtils.hasText(name), "name", name);  
    // 仅当 StringUtils.hasText(name) 为 true 时, 会拼接这个like语句到WHERE中  
    // 其实就是对下面代码的简化  
    if (StringUtils.hasText(name)) {  
     wrapper.like("name", name);  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    实体对象作为条件
    调用构造函数创建一个Wrapper对象时,可以传入一个实体对象。后续使用这个Wrapper时,会以实体对象中的非空属性,构建WHERE条件(默认构建等值匹配的WHERE条件,这个行为可以通过实体类里各个字段上的@TableField注解中的condition属性进行改变)例如:@TableField(condition = SqlCondition.LIKE) // 配置该字段使用like进行拼接
    SqlCondition类中预定义了一些字符串以供选择

    package com.baomidou.mybatisplus.annotation;  
      
    public class SqlCondition {  
        //下面的字符串中, %s 是占位符, 第一个 %s 是列名, 第二个 %s 是列的值  
        public static final String EQUAL = "%s=#{%s}";  
        public static final String NOT_EQUAL = "%s<>#{%s}";  
        public static final String LIKE = "%s LIKE CONCAT('%%',#{%s},'%%')";  
        public static final String LIKE_LEFT = "%s LIKE CONCAT('%%',#{%s})";  
        public static final String LIKE_RIGHT = "%s LIKE CONCAT(#{%s},'%%')";  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    SqlCondition中提供的配置比较有限,有时需要自己拼接
    例如:
    @TableField(condition = “%s > #{%s}”) 表示大于

    lambda条件构造器

    lambda条件构造器,支持lambda表达式,可以不必像普通条件构造器一样,以字符串形式指定列名,它可以直接以实体类的方法引用来指定列。

     LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();  
      wrapper.like(User::getName, "黄").lt(User::getAge, 30);  
      List<User> users = userMapper.selectList(wrapper);  
      users.forEach(System.out::println);  
    
    • 1
    • 2
    • 3
    • 4

    lambda条件构造器可以链式调用,使代码更简洁

     LambdaQueryChainWrapper<User> chainWrapper = new LambdaQueryChainWrapper<>(userMapper);  
      List<User> users = chainWrapper.like(User::getName, "黄").gt(User::getAge, 30).list();  
      users.forEach(System.out::println); 
    
    • 1
    • 2
    • 3

    三、代码示例

    查询简单示例

    	@Test
        void selectTest(){
    
            //QueryWrapper查询
            List<User> userList = userService.getBaseMapper().selectList(
                    new QueryWrapper<User>().eq("name","Jack")
            );
            userList.forEach(System.out::println);
            //LambdaQueryWrapper查询
            List<User> userList1 = userService.getBaseMapper().selectList(
                    new LambdaQueryWrapper<User>().eq(User::getName,"Jack")
            );
            userList1.forEach(System.out::println);
    
            //LambdaQueryChainWrapper查询
            List<User> userList2 = userService.lambdaQuery().eq(User::getName,"Jack").list();
            userList2.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    update 简单示例

    @Test
        void updateTest(){
            //UpdateWrapper更新
            boolean flag = userService.update(
                    new UpdateWrapper<User>()
                    .eq("name","Jack")
                    .set("age",20)
            );
            System.out.println(flag);
    
            //LambdaUpdateWrapper更新
            boolean flag1 = userService.update(
                    new LambdaUpdateWrapper<User>()
                    .in(User::getId,new int[]{1,2})
                    .set(User::getAge,18)
            );
            System.out.println(flag1);
    
            boolean flag2 = userService.lambdaUpdate()
                    .in(User::getId,new String[]{"1","2"})
                    .set(User::getAge,17)
                    .update();
            System.out.println(flag2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    insert 简单示例:

    @Test
        void insertTest(){
            User user1 = new User();
            user1.setId(6L);
            user1.setName("Mic");
            user1.setAge(29);
            user1.setEmail("test6@baomidou.com");
            int count = userMapper.insert(user1);
    
            System.out.println(count);
    
            User user2 = new User();
            user2.setId(7L);
            user2.setName("Sam");
            user2.setAge(23);
            user2.setEmail("test7@baomidou.com");
            boolean falg = userService.save(user2);
    
            System.out.println(falg);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    delete示例:

    @Test
        void deleteTest(){
            int result = userMapper.delete(new QueryWrapper<User>().eq("id",6));
            System.out.println(result);
    
            int result2 = userMapper.delete(new LambdaQueryWrapper<User>().eq(User::getId,7));
            System.out.println(result);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    分页查询示例

    mp使用分页查询前,需要先把分页查询查插件注册到spring中

    package com.example.demo.config;
    
    import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MybatisPlusConfig {
    
        /** 新版mp **/
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            return interceptor;
        }
        /** 旧版mp 用 PaginationInterceptor **/
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    分页查询示例:

     @Test
        void selectpageTest(){
            //QueryWrapper查询
            IPage<User> pageList = userService.getBaseMapper().selectPage(
                    new Page<User>(0,2),
                    new QueryWrapper<User>()
            );
    
            List<User> userList = pageList.getRecords();
            userList.forEach(System.out::println);
    
            IPage<User> pageList1 = userService.getBaseMapper().selectPage(
                    new Page<User>(0,2),
                    new LambdaQueryWrapper<User>()
            );
    
            List<User> userList1 = pageList1.getRecords();
            userList1.forEach(System.out::println);
    
            IPage<User> pageList2 = userService.lambdaQuery().page(new Page<User>(0,2));
    
            List<User> userList2 = pageList2.getRecords();
            userList2.forEach(System.out::println);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    分页查询默认会先查count总条数,如果不希望查count,可以通过Page的重载构造函数,指定isSearchCount为false即可

    public Page(long current, long size, boolean isSearchCount)
    
    • 1

    使用mybatis原生的方式做查询时,如果需要使用分页,可以在接口上加上page参数:Param(“page”) Page<> page,即可使用分页方法,而无需在sql中写分页语句

    四、总结

    mp在mybatis的基础上做了增强,提供许多简单的CRUD方法,我们拿来直接用即可。而且mp也保留了原生的mybatis的功能,我们也可以使用原生的在mapper.xml中写sql的方式执行crud。本文只是介绍了mybatis-plus的基础功能,方便新手快速入门,mybatis-plus还有许多有趣的功能,可以自行去官网查阅。

  • 相关阅读:
    mac 上 安装配置mat
    nacos docker compose安装配置
    微信小程序如何转云开发
    第1章 Java 概述及开发环境搭建
    js刷题常用基础函数&常用快捷键
    Python新手入门
    使用ML.Net轻松接入AI模型!
    [附源码]Python计算机毕业设计Django的在线作业批改系统
    含文档+PPT+源码等]精品基于Uniapp+SSM实现的日常饮食管理APP[包运行成功]计算机毕业设计Android项目源码
    Andriod 简单控件
  • 原文地址:https://blog.csdn.net/qq_34609889/article/details/126243411