• MyBatis-Plus为简化开发而生


    简介

    MyBatis-Plus 简称 MP是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
    在这里插入图片描述
    他们的愿景是成为 MyBatis 最好的搭档,就像魂斗罗中的 1P、2P,基友搭配,效率翻倍。

    特性

    • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

    • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作

    • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求

    • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错

    • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题

    • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用

    • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询

    • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库

    支持数据库

    任何能使用 MyBatis 进行 CRUD, 并且支持标准 SQL 的数据库,具体支持情况如下,如果不在下列表查看分页部分教程 PR 您的支持。

    • MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb,informix,TDengine,redshift

    • 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库,优炫数据库。

    框架结构

    在这里插入图片描述

    SSM传统编程模式

    在这里插入图片描述

    快速开始

    现有一张User表

    -- 用户表:user
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user`  (
      `id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
      `name` VARCHAR(30) DEFAULT NULL COMMENT '姓名',
      `age` INT(11) DEFAULT NULL COMMENT '年龄',
      `email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
      `manager_id` BIGINT(20) DEFAULT NULL COMMENT '直属上级id',
      `create_time` DATETIME(0) DEFAULT NULL COMMENT '创建时间',
      `update_time` DATETIME DEFAULT NULL COMMENT '修改时间',
      `version` INT(11) DEFAULT '1' COMMENT '版本',
      `deleted` INT(1) DEFAULT '0' COMMENT '逻辑删除标识(0.未删除,1.已删除)'
    ) ENGINE=INNODB CHARSET=UTF8;
    INSERT INTO `user`(`id`,`name`,`age`,`email`,`manager_id`,`create_time`) VALUES
    (1087982257332887553, '徐源', 28, 'boss@baomidou.com', NULL, '2023-06-28 09:20:20'),
    (1088248166370832385, 'Tony', 25, 'wtf@baomidou.com', 1087982257332887553, '2023-06-28 11:12:22'),
    (1088250446457389058, 'Jack', 28, 'lyw@baomidou.com', 1088248166370832385, '2023-06-28 08:31:16'),
    (1094590409767661570, 'Rose', 31, 'zjq@baomidou.com', 1088248166370832385, '2023-06-27 09:15:15'),
    (1094592041087729666, 'Lemon', 32, 'lhm@baomidou.com', 1088248166370832385, '2023-06-28 09:48:16');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    项目添加依赖

    <properties>
    	<java.version>1.8java.version>
    	<mybatis-plus.version>3.3.2mybatis-plus.version>
    properties>
    
    <dependencies>
    	<dependency>
    		<groupId>org.springframework.bootgroupId>
    		<artifactId>spring-boot-starterartifactId>
    	dependency>
    	<dependency>
    		<groupId>org.springframework.bootgroupId>
    		<artifactId>spring-boot-starter-testartifactId>
    		<scope>testscope>
    	dependency>
    	<dependency>
    		 <groupId>org.projectlombokgroupId>
             <artifactId>lombokartifactId>
             <optional>trueoptional>
    	dependency>
    	<dependency>
    		<groupId>mysqlgroupId>
    		<artifactId>mysql-connector-javaartifactId>
    		<scope>runtimescope>
    	dependency>
    	<dependency>
    		<groupId>com.baomidougroupId>
    		<artifactId>mybatis-plus-boot-starterartifactId>
    		<version>${mybatis-plus.version}version>
    	dependency>
    dependencies>
    
    • 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

    配置

    application.yml 配置文件中添加数据库的相关配置:

    # 配置数据源
    spring:
      datasource:
        url: jdbc:mysql://121.89.226.84:3306/mybatis-plus?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: root
    
    # 配置日志
    logging:
      level:
        root: warn
        com.xkw.mp.crud.mapper: trace
      pattern:
        console: '%p%m%n'
    
    mybatis-plus:
      mapper-locations: ['classpath:/mapper/*Mapper.xml']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:

    @SpringBootApplication
    @MapperScan("com.xkw.mp.crud.mapper")
    public class CrudApp {
        public static void main(String[] args) {
            SpringApplication.run(ServiceApp.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    编码

    编写实体类 User.java(此处使用了 Lombok简化代码)

    @Data
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
        private Long managerId;
        private LocalDateTime createTime;
        private  LocalDateTime updateTime;
        // 乐观锁注解
        @Version
        private  Integer version = 1;
    	// 逻辑删除标识(0.未删除,1.已删除)
        @TableLogic
        @TableField(select = false)
        private  Integer deleted = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    编写 Mapper 包下的 UserMapper接口

    public interface UserMapper extends BaseMapper<User> {
    
    }
    
    • 1
    • 2
    • 3

    编写 Service 包下的 IUserService接口(非必须)

    public interface IUserService extends IService<User> {
    	
    }
    
    • 1
    • 2
    • 3
    @Service
    public class UserService extends ServiceImpl<UserMapper, User> implements IUserService {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    测试

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = CrudApp.class)
    @Slf4j
    public class SampleTest {
        @Autowired
        UserMapper userMapper;
        @Autowired
        IUserService userService;
    
        @Test
        public void testSelect() {
            List<User> users01 =  userMapper.selectList(null);
            Assert.assertEquals(8, users01.size());
            users01.forEach(user -> log.info(user.getName()));
    
            List<User> users02 = userService.list();
            Assert.assertEquals(8, users02.size());
            users02.forEach(user -> log.info(user.getName()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    以上代码可以通过代码生成器快速生成,并且可以定制化生成:

    AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
    在这里插入图片描述

    CRUD

    通用Mapper

    通用 CRUD 封装BaseMapper 接口,为 Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器;

    泛型 T 为任意实体对象;

    参数 Serializable 为任意类型主键 Mybatis-Plus 不推荐使用复合主键约定每一张表都有自己的唯一 id 主键;

    对象 Wrapper 为 条件构造器。

    /**
     * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
     * 

    这个 Mapper 支持 id 泛型

    * * @author hubin * @since 2016-01-23 */
    public interface BaseMapper<T> extends Mapper<T> { /** * 插入一条记录 * * @param entity 实体对象 */ int insert(T entity); /** * 根据 ID 删除 * * @param id 主键ID */ int deleteById(Serializable id); /** * 根据 columnMap 条件,删除记录 * * @param columnMap 表字段 map 对象 */ int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); /** * 根据 entity 条件,删除记录 * * @param wrapper 实体对象封装操作类(可以为 null) */ int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper); /** * 删除(根据ID 批量删除) * * @param idList 主键ID列表(不能为 null 以及 empty) */ int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); /** * 根据 ID 修改 * * @param entity 实体对象 */ int updateById(@Param(Constants.ENTITY) T entity); /** * 根据 whereEntity 条件,更新记录 * * @param entity 实体对象 (set 条件值,可以为 null) * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) */ int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper); /** * 根据 ID 查询 * * @param id 主键ID */ T selectById(Serializable id); /** * 查询(根据ID 批量查询) * * @param idList 主键ID列表(不能为 null 以及 empty) */ List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); /** * 查询(根据 columnMap 条件) * * @param columnMap 表字段 map 对象 */ List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); /** * 根据 entity 条件,查询一条记录 * * @param queryWrapper 实体对象封装操作类(可以为 null) */ T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); /** * 根据 Wrapper 条件,查询总记录数 * * @param queryWrapper 实体对象封装操作类(可以为 null) */ Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); /** * 根据 entity 条件,查询全部记录 * * @param queryWrapper 实体对象封装操作类(可以为 null) */ List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); /** * 根据 Wrapper 条件,查询全部记录 * * @param queryWrapper 实体对象封装操作类(可以为 null) */ List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); /** * 根据 Wrapper 条件,查询全部记录 *

    注意: 只返回第一个字段的值

    * * @param queryWrapper 实体对象封装操作类(可以为 null) */
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); /** * 根据 entity 条件,查询全部记录(并翻页) * * @param page 分页查询条件(可以为 RowBounds.DEFAULT) * @param queryWrapper 实体对象封装操作类(可以为 null) */ <E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); /** * 根据 Wrapper 条件,查询全部记录(并翻页) * * @param page 分页查询条件 * @param queryWrapper 实体对象封装操作类 */ <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) 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
    • 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
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115

    通用Service

    通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆;

    泛型 T 为任意实体对象;

    建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类;

    对象 Wrapper 为 条件构造器。

    Save

    // 插入一条记录(选择字段,策略插入)
    boolean save(T entity);
    // 插入(批量)
    boolean saveBatch(Collection<T> entityList);
    // 插入(批量)
    boolean saveBatch(Collection<T> entityList, int batchSize);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    通用 insertBatch 为什么放在 service 层处理

    • SQL 长度有限制海量数据量单条 SQL 无法执行,就算可执行也容易引起内存泄露 JDBC 连接超时等

    • 不同数据库对于单条 SQL 批量语法不一样不利于通用

    • 目前的解决方案:循环预处理批量提交,虽然性能比单 SQL 慢但是可以解决以上问题。

    SaveOrUpdate

    // 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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Remove

    // 根据 queryWrapper 设置的条件,删除记录
    boolean remove(Wrapper<T> queryWrapper);
    // 根据 ID 删除
    boolean removeById(Serializable id);
    // 根据 columnMap 条件,删除记录
    boolean removeByMap(Map<String, Object> columnMap);
    // 删除(根据ID 批量删除)
    boolean removeByIds(Collection<? extends Serializable> idList);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Update

    // 根据 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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Get

    // 根据 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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    List

    // 查询所有
    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Page

    // 无条件分页查询
    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Chain

    query

    // 链式查询 普通
    QueryChainWrapper<T> query();
    // 链式查询 lambda 式。注意:不支持 Kotlin
    LambdaQueryChainWrapper<T> lambdaQuery();
    
    // 示例:
    query().eq("column", value).one();
    lambdaQuery().eq(Entity::getId, value).list();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    update

    / 链式更改 普通
    UpdateChainWrapper<T> update();
    // 链式更改 lambda 式。注意:不支持 Kotlin
    LambdaUpdateChainWrapper<T> lambdaUpdate();
    
    // 示例:
    update().eq("column", value).remove();
    lambdaUpdate().eq(Entity::getId, value).update(entity);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    条件构造器

    MyBatis-Plus条件构造器(MyBatis-Plus Condition Wrapper)是 MyBatis-Plus 框架提供的一个强大的查询条件构建工具,用于在 SQL 查询中添加多个动态条件;

    通过使用条件构造器,您可以方便地根据不同的情况动态构建查询条件,并且避免了手动编写复杂的 SQL 语句。它提供了一套简单直观的 API,使得构建和管理查询条件变得更加灵活和高效。

    使用条件构造器,您可以轻松实现以下常见操作:

    等值判断 eq(column, value) 示例:

    QueryWrapper<User> query = new QueryWrapper<>();
    query.eq("name", "Tony");
    
    • 1
    • 2

    不等值判断 ne(column, value) 示例:

    QueryWrapper<User> query = new QueryWrapper<>();
    query.ne("age", 28);
    
    • 1
    • 2

    大于判断 gt(column, value)示例:gt(“salary”, 5000)

    小于判断 lt(column, value)示例:lt(“create_time”, LocalDateTime.now())

    范围判断 between(column, value1, value2)示例:between(“price”, 100, 200)

    模糊查询 like(column, value)示例:like(“title”, “%keyword%”)

    除此之外,条件构造器还支持排序、分页、子查询等功能,以及各种逻辑运算符(与、或、非)、函数计算等高级操作。

    Lambda条件构造器

    在 MyBatis-Plus 中,除了常规的条件构造器外,还提供了一种更为简洁、方便的 Lambda 条件构造器(Lambda Query Wrapper);

    使用 Lambda 条件构造器,您可以通过 Java 8 中引入的 Lambda 表达式来编写查询条件;

    使用 Lambda 条件构造器,能够让代码更加精炼,并且具有语法高亮和类型安全性,防误写

    下面是几个示例:

    等值判断 eq(column, value) 示例:

    LambdaQueryWrapper<User> lambdaQuery = Wrappers.lambdaQuery();
    lambdaQuery.eq(User::getName, "Tony");
    
    • 1
    • 2

    不等值判断 ne(column, value) 示例:

    LambdaQueryWrapper<User> lambdaQuery = Wrappers.lambdaQuery();
    lambdaQuery.ne(User::getAge, 28);
    
    • 1
    • 2

    大于判断:wrapper.gt(User::getSalary, 5000)

    小于判断:wrapper.lt(User::getCreateTime, LocalDateTime.now())

    范围判断:wrapper.between(User::getPrice, 100, 200)

    模糊查询:wrapper.like(User::getTitle, "%keyword%")

    Lambda 条件构造器还支持排序、分页、子查询等功能,以及各种逻辑运算符(与、或、非)、函数计算等高级操作,使得条件拼接变得更加灵活和简单。

    通过使用 MyBatis-Plus 的 Lambda 条件构造器,您可以轻松实现复杂查询,减少手动编写 SQL 的工作量,并且更容易维护和理解代码。它大大简化了查询条件的构建过程,提升了开发效率和代码质量。

    Case

    查询,徐姓或者年龄大于等于25,按照年龄降序排列,年龄相同则按照id升序排列

    SQL:name like ‘徐%’ or age>=25 order by age desc,id asc

    QueryWrapper<User> query = new QueryWrapper<>();
    query.likeRight("name", "徐")
    	 .or().ge("age", 25)
         .orderByDesc("age")
         .orderByAsc("id");
    List<User> list = userMapper.selectList(query);
    list.forEach(System.out::println);
    
    LambdaQueryWrapper<User> lambdaQuery = Wrappers.lambdaQuery();
    lambdaQuery.likeRight(User::getName, "徐")
                .or().ge(User::getAge, 25)
                .orderByDesc(User::getAge)
                 .orderByAsc(User::getId);
    List<User> list02 = userMapper.selectList(lambdaQuery);
    list02.forEach(System.out::println);
    
    List<User> list03 = userService.lambdaQuery()
    		     .likeRight(User::getName, "涂")
    			 .or().ge(User::getAge, 25)
                 .orderByDesc(User::getAge)
                 .orderByAsc(User::getId)
                 .list();
    list03.forEach(System.out::println);
    
    /**
    * DEBUG==>  Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (name LIKE ? OR age >= ?) ORDER BY age DESC,id ASC 
    * DEBUG==> Parameters: 徐%(String), 20(Integer)
    */
    
    • 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

    查询,徐姓或者(龄小于40并且年龄大于28并且邮箱不为空)

    SQL:name like ‘徐%’ or (age < 40 and age > 28 and email is not null)

    QueryWrapper<User> query = new QueryWrapper<>();
    query.likeRight("name", "徐")
          .or(q -> q.between("age", 28, 40)
          .isNotNull("email"));
    List<User> list01 = userMapper.selectList(query);
    list01.forEach(System.out::println);
    
    LambdaQueryWrapper<User> lambdaQuery = Wrappers.lambdaQuery();
    lambdaQuery.likeRight(User::getName, "徐")
               .or(q -> q.between(User::getAge, 28, 40)
               .isNotNull(User::getName));
    List<User> list02 = userMapper.selectList(lambdaQuery);
    list02.forEach(System.out::println);
    
    /**
    * DEBUG==>  Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (name LIKE ? OR (age BETWEEN ? AND ? AND name IS NOT NULL)) 
    * DEBUG==> Parameters: 徐%(String), 28(Integer), 40(Integer)
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    查询指定字段,名字中包含雨并且年龄小于40

    QueryWrapper<User> query = new QueryWrapper<>();
    query.select("name", "age")
    	 .like("name", "雨")
         .lt("age", 40);
    List<User> list01 = userMapper.selectList(query);
    list01.forEach(System.out::println);
    
    LambdaQueryWrapper<User> lambdaQuery = Wrappers.lambdaQuery();
    lambdaQuery.select(User::getName, User::getAge)
               .like(User::getName, "雨")
               .lt(User::getAge, 40);
    List<User> list02 = userMapper.selectList(lambdaQuery);
    list02.forEach(System.out::println);
    
    /**
    * DEBUG==>  Preparing: SELECT name,age FROM user WHERE (name LIKE ? AND age < ?) 
    * DEBUG==> Parameters: %雨%(String), 40(Integer)
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    查询,创建日期为2023年06月28日并且直属上级为徐姓

    SQL:date_format(create_time, ‘%Y-%m-%d’)=‘2023-06-28’ and manager_id in (select id from user where name like ‘徐%’)

    QueryWrapper<User> query = new QueryWrapper<>();
    query.apply("DATE_FORMAT(create_time,'%Y-%m-%d')={0}", "2023-06-28")
                .inSql("manager_id", "SELECT id FROM `user` WHERE `name` LIKE '徐%'");
    List<User> list01 = userMapper.selectList(query);
    list01.forEach(System.out::println);
    
    LambdaQueryWrapper<User> lambdaQuery = Wrappers.lambdaQuery();
    lambdaQuery.apply("DATE_FORMAT(create_time,'%Y-%m-%d')={0}", "2023-06-28")
    	.inSql(User::getManagerId, "SELECT id FROM `user` WHERE `name` LIKE '徐%'");
    List<User> list02 = userMapper.selectList(lambdaQuery);
    list02.forEach(System.out::println);
    
    /**
    * DEBUG==>  Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (DATE_FORMAT(create_time,'%Y-%m-%d')=? AND manager_id IN (SELECT id FROM `user` WHERE `name` LIKE '徐%')) 
    * DEBUG==> Parameters: 2023-06-28(String)
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    主键策略

    MyBatis-Plus 提供了一种灵活且开发友好的主键策略,可以方便地生成和管理实体类的主键。以下是 MyBatis-Plus 主要支持的几种主键策略:

    • 自增主键(AUTO_INCREMENT):这是最常见的主键策略之一,数据库会自动为每条记录分配一个唯一的递增值作为主键;

    • UUID 主键:使用 Universally Unique Identifier (UUID) 作为唯一标识符,在插入数据时会自动生成一个长度为 32 的唯一字符串,并将其作为主键;

    • 分布式 ID:提供了多种分布式 ID 策略,如雪花算法 Snowflake、Leaf、Ulid 等。这些策略通过在不同节点之间进行协调来产生全局唯一的 ID;

    • 自定义主键生成器:允许开发者根据具体业务需求自定义主键生成逻辑,只需要实现 KeyGenerator 接口并配置到相应的实体上即可。

    对于自增主键,MyBatis-Plus 在默认情况下会假设数据库会返回自动生成的主键,并自动将其设置回实体对象中。

    若您使用的数据库无法自动生成主键或想手动控制主键生成过程,可以设置 @TableId注解的 type 属性为 IdType.INPUT,然后通过编码方式设置主键值。

    对于 UUID 主键或分布式 ID,只需使用 @TableId注解指定主键生成策略为IdType.UUIDIdType.ID_WORKER 等即可。MyBatis-Plus 将会在插入数据时自动生成相应的主键。

    若想自定义主键生成逻辑,可以实现 KeyGenerator 接口,并将该自定义主键生成器注入到 IOC 容器中。然后在实体类的 @TableId 注解中设置 generator 属性为自定义主键生成器的名字。

    总而言之,MyBatis-Plus 提供了多种灵活且易用的主键策略,能够满足不同项目和业务场景下的需求。开发者可以根据具体情况选择合适的主键生成方式,并通过简单的配置即可轻松管理实体对象的主键。

    插件

    分页插件

    分页插件(PaginationInterceptor):分页是在大部分应用中都需要处理的需求之一;MyBatis-Plus 的分页插件可以帮助我们方便地进行数据库查询结果的分页操作。通过使用该插件,我们可以很容易地实现分页查询并获取分页结果。

    @Bean
    @ConditionalOnMissingBean
    public PaginationInterceptor paginationInterceptor() {
    	PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
    	// 单页限制 500 条,小于 0 如 -1 不受限制
    	paginationInterceptor.setLimit(-1);
    	// 溢出总页数后是否进行处理(默认不处理)
    	paginationInterceptor.setOverflow(true);
    	return paginationInterceptor;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    LambdaQueryWrapper<User> query = new LambdaQueryWrapper<>();
    query.ge(User::getAge, 26)
                    .orderByDesc(User::getCreateTime);
    Page<User> page = new Page<>(1, 2);
    IPage<Map<String, Object>> iPage = userMapper.selectMapsPage(page, query);
    System.out.println("总页数:" + page.getPages());
    System.out.println("总记录数:" + iPage.getTotal());
    List<Map<String, Object>> list = iPage.getRecords();
    list.forEach(System.out::println);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    乐观锁插件

    数据库乐观锁插件(OptimisticLockerInterceptor):乐观锁是一种并发控制机制,通过在数据表中添加一个版本号字段实现。MyBatis-Plus 的乐观锁插件可以自动处理带有乐观锁的更新操作,确保并发情况下不会出现数据被覆盖或丢失的问题。

    /**
     * 引入乐观锁插件
     */
    @Bean
    @ConditionalOnMissingBean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    @Data
    public class User {
        /**
         * 乐观锁注解
         */
        @Version
        private  Integer version;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    User user = userMapper.selectById(1673973063479255042L);
    user.setAge(30);
    
    System.out.println("开始休息,在修改的过程中,有其他用户对数据进行了更新...");
    Thread.sleep(10000);
    System.out.println("去数据库修改该条数据,并将version增加一个版本");
            
    int rows = userMapper.updateById(user);
    System.out.println("影响行数:"+rows);
    
    /**
    * DEBUG==>  Preparing: SELECT id,name,age,email,manager_id,create_time,update_time,version,deleted FROM user WHERE id=? 
    * DEBUG==> Parameters: 1673973063479255042(Long)
    * TRACE<==    Columns: id, name, age, email, manager_id, create_time, update_time, version, deleted
    * TRACE<==        Row: 1673973063479255042, 王二狗, 30, null, 1088248166370832385, 2023-06-28 00:34:14, null, 5, 0
    * DEBUG<==      Total: 1
    * 开始休息,在修改的过程中,有其他用户对数据进行了更新...
    * 去数据库修改该条数据,并将version增加一个版本
    * DEBUG==>  Preparing: UPDATE user SET name=?, age=?, manager_id=?, create_time=?, version=?, deleted=? WHERE id=? AND version=? 
    * DEBUG==> Parameters: 王二狗(String), 30(Integer), 1088248166370832385(Long), 2023-06-28T00:34:14(LocalDateTime), 6(Integer), 0(Integer), 1673973063479255042(Long), 5(Integer)
    * DEBUG<==    Updates: 0
    * 影响行数:0
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

  • 相关阅读:
    QT 发布文章遇到问题解决方案
    Uniapp小程序MBG 开发踩坑日记
    APISpace 验证码短信API接口案例代码
    ts 泛型基础介绍
    MySQL|聚合函数
    Java面试题-Java核心基础-第十二天(SPI机制)
    2.26回顾章节主体线索脉络,课程要求(评分)
    1158. 市场分析 I
    如何解决 npm ERR! Cannot read properties of null (reading ‘pickAlgorithm‘)报错问题
    【Python】逆向与爬虫的故事
  • 原文地址:https://blog.csdn.net/tuyuan2012/article/details/133769023