MyBatisPlus学习笔记(SpringBoot版)

news2024/9/25 23:24:31

MyBatisPlus学习笔记(SpringBoot版)

      • 一、MyBatis-Plus简介
        • 1、简介
        • 2、特性
        • 3、支持数据库
        • 4、框架结构
        • 5、代码及文档地址
      • 二、入门案例
        • 1、开发环境
        • 2、创建数据库及表
          • 2.1 创建表
          • 2.2 添加数据
        • 3、创建Spring Boot工程
          • 3.1 初始化工程
          • 3.2 引入依赖
          • 3.3 idea中安装lombok插件
        • 4、编写代码
          • 4.1 配置application.yml
          • 4.2 启动类
          • 4.3 添加实体
          • 4.4 添加UserMapper
          • 4.5 测试
          • 4.6 查看日志
      • 三、基本CRUD
        • 1、BaseMapper
        • 2、插入
        • 3、删除
          • 3.1 通过id删除记录
          • 3.2 通过id批量删除记录
          • 3.3 通过map条件删除记录
        • 4、修改
        • 5、查询
          • 5.1 根据id查询用户信息
          • 5.2 根据多个id查询多个用户信息
          • 5.3 通过map条件查询用户信息
          • 5.4 查询所有数据
          • 5.5 自定义mapper查询
        • 6、通用Service
          • 6.1 IService
            • 6.1.1 IService源码:
            • 6.1.2 ServiceImpl源码:
          • 6.2 创建Service接口和实现类
          • 6.3 测试查询记录数
          • 6.4 测试批量插入
      • 四、常用注解
        • 1、@TableName
        • 2、@TableId
        • 3、@TableField
        • 4、@TableLogic
            • 4.1 逻辑删除
            • 4.2 实现逻辑删除
            • 4.3 实体类中添加逻辑删除属性
            • 4.4 测试
      • 五、条件构造器和常用接口
        • 1、wapper介绍
        • 2、QueryWrapper(查询和删除)
            • 2.1、组装查询条件
            • 2.2、组装排序条件
            • 2.3、组装删除条件
            • 2.4、条件的优先级
            • 2.5、组装select子句
            • 2.6、实现子查询
        • 3、UpdateWrapper(修改)
        • 4、condition
        • 5、LambdaQueryWrapper
        • 6、LambdaUpdateWrapper
      • 六、插件
        • 1、分页插件
            • 1.1、添加配置类
            • 1.2、测试
        • 2、xml自定义分页
            • 2.1、UserMapper中定义接口方法
            • 2.2、UserMapper.xml中编写SQL
            • 2.3、测试

一、MyBatis-Plus简介

1、简介

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

愿景
我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

在这里插入图片描述

2、特性

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

3、支持数据库

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

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

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

4、框架结构

在这里插入图片描述

5、代码及文档地址

官方地址: https://www.baomidou.com/

代码发布地址:
Github: https://github.com/baomidou/mybatis-plus
Gitee: https://gitee.com/baomidou/mybatis-plus

文档发布地址: https://www.baomidou.com/pages/24112f/

二、入门案例

1、开发环境

IDE:idea 2020.3
JDK:JDK8+
构建工具:maven 3.6.3
MySQL版本:MySQL 8.0.28
Spring Boot:2.6.6
MyBatis-Plus:3.2.0

2、创建数据库及表

2.1 创建表
CREATE DATABASE `study_mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
use `study_mybatis_plus`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.2 添加数据
INSERT INTO user (id, name, age, email) VALUES
(001, 'Mp01', 21, 'Mp01@baomidou.com'),
(002, 'Mp02', 20, 'Mp02@baomidou.com'),
(003, 'Mp03', 25, 'Mp03@baomidou.com'),
(004, 'Mp04', 21, 'Mp04@baomidou.com'),
(005, 'Mp05', 24, 'Mp05@baomidou.com');

3、创建Spring Boot工程

3.1 初始化工程

使用 Spring Initializr 快速初始化一个 Spring Boot 工程
在这里插入图片描述
在这里插入图片描述

3.2 引入依赖

完整pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.tigerhhzz</groupId>
    <artifactId>springboot-mybatisplus-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-mybatisplus-demo</name>
    <description>Demo project for Spring Boot MP</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- 包含spirng Mvc ,tomcat的包包含requestMapping restController 等注解 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <!--mysql数据库 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <!-- mybatis版本必须与druid版本兼容,否则无法创建DataSource -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>

        <!-- 引入freemarker模板引擎供mp生成代码-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <!--mp代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.0</version>
        </dependency>
        <!-- hutool工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.3</version>
        </dependency>
        <!-- lombok注解-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 日志打印-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <!-- 单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.3 idea中安装lombok插件

在这里插入图片描述

4、编写代码

4.1 配置application.yml
server:
  port: 8082
  servlet:
    context-path: /

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    #  test-mybatis
    url: jdbc:mysql://127.0.0.1:3306/study_mybatis_plus?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: 123456
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      write-dates-as-timestamps: false

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    auto-mapping-behavior: full
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:mapper/**/*Mapper.xml
4.2 启动类
package com.tigerhhzz.springbootmybatisplusdemo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author tigerhhzz
 * @date 2023/4/28 9:16
 */
@Slf4j
@SpringBootApplication
public class SpringbootMybatisplusDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisplusDemoApplication.class, args);
        log.info("SpringbootMybatisplusDemoApplication启动成功~~~~^…^~~~~^…^~~~~~^…^~~~~");
    }
}

4.3 添加实体
package com.tigerhhzz.springbootmybatisplusdemo.domain;

import lombok.Data;

/**
 * @author tigerhhzz
 * @date 2023/5/4 16:09
 */
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;

}

User类编译之后的结果:
在这里插入图片描述

4.4 添加UserMapper

BaseMapper是MyBatis-Plus提供的模板mapper,其中包含了基本的CRUD方法,泛型为操作的 实体类型

package com.tigerhhzz.springbootmybatisplusdemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tigerhhzz.springbootmybatisplusdemo.domain.User;

/**
 * @author tigerhhzz
 */
@Repository
public interface UserMapper extends BaseMapper<User> {
}
4.5 测试

IDEA在 userMapper 处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确 的执行。
为了避免报错,可以在mapper接口上添加 @Repository 注解

    @Autowired
    UserMapper userMapper;


    @Test
    public void testSelectList(){
    //selectList()根据MP内置的条件构造器查询一个list集合,null表示没有条件,即查询所有
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
4.6 查看日志

在这里插入图片描述

三、基本CRUD

1、BaseMapper

MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现,我们可以直接使用,接口如 下:

/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.core.mapper;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/*

               :`
                    .:,
                     :::,,.
             ::      `::::::
             ::`    `,:,` .:`
             `:: `::::::::.:`      `:';,`
              ::::,     .:::`   `@++++++++:
               ``        :::`  @+++++++++++#
                         :::, #++++++++++++++`
                 ,:      `::::::;'##++++++++++
                 .@#@;`   ::::::::::::::::::::;
                  #@####@, :::::::::::::::+#;::.
                  @@######+@:::::::::::::.  #@:;
           ,      @@########':::::::::::: .#''':`
           ;##@@@+:##########@::::::::::: @#;.,:.
            #@@@######++++#####'::::::::: .##+,:#`
            @@@@@#####+++++'#####+::::::::` ,`::@#:`
            `@@@@#####++++++'#####+#':::::::::::@.
             @@@@######+++++''#######+##';::::;':,`
              @@@@#####+++++'''#######++++++++++`
               #@@#####++++++''########++++++++'
               `#@######+++++''+########+++++++;
                `@@#####+++++''##########++++++,
                 @@######+++++'##########+++++#`
                @@@@#####+++++############++++;
              ;#@@@@@####++++##############+++,
             @@@@@@@@@@@###@###############++'
           @#@@@@@@@@@@@@###################+:
        `@#@@@@@@@@@@@@@@###################'`
      :@#@@@@@@@@@@@@@@@@@##################,
      ,@@@@@@@@@@@@@@@@@@@@################;
       ,#@@@@@@@@@@@@@@@@@@@##############+`
        .#@@@@@@@@@@@@@@@@@@#############@,
          @@@@@@@@@@@@@@@@@@@###########@,
           :#@@@@@@@@@@@@@@@@##########@,
            `##@@@@@@@@@@@@@@@########+,
              `+@@@@@@@@@@@@@@@#####@:`
                `:@@@@@@@@@@@@@@##@;.
                   `,'@@@@##@@@+;,`
                        ``...``

 _ _     /_ _ _/_. ____  /    _
/ / //_//_//_|/ /_\  /_///_/_\      Talk is cheap. Show me the code.
     _/             /
 */

/**
 * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
 * <p>这个 Mapper 支持 id 泛型</p>
 *
 * @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 条件,查询全部记录
     * <p>注意: 只返回第一个字段的值</p>
     *
     * @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);
}

2、插入

    @Test
    public void testInsert(){
        User user = new User();
        user.setName("Mp06");
        user.setAge(23);
        user.setEmail("Mp06@baomidou.com");

        int result = userMapper.insert(user);
        System.out.println("受影响行数:"+result);

        System.out.println("id自动获取:"+user.getId());
    }

最终执行的结果,所获取的id为1475754982694199298
这是因为MyBatis-Plus在实现插入数据时,会默认基于雪花算法的策略生成id
在这里插入图片描述

查看数据库:
在这里插入图片描述

3、删除

3.1 通过id删除记录
    @Test
    public void testDeleteById(){
        //通过id删除用户信息
        //DELETE FROM user WHERE id=?
        int result = userMapper.deleteById(1654046614353891329L);
        System.out.println("受影响行数:"+result);
    }
3.2 通过id批量删除记录
    @Test
    public void testDeleteBatchIds(){
        //通过多个id批量删除
        //DELETE FROM user WHERE id IN ( ? , ? , ? )
        List<Long> idList = Arrays.asList(1L, 2L, 3L);
        int result = userMapper.deleteBatchIds(idList);
        System.out.println("受影响行数:"+result);
    }
3.3 通过map条件删除记录
    @Test
    public void testDeleteByMap(){
        //根据map集合中所设置的条件删除记录
        //DELETE FROM user WHERE name = ? AND age = ?
        Map<String, Object> map = new HashMap<>();
        map.put("age", 23);
        map.put("name", "张三");
        int result = userMapper.deleteByMap(map);
        System.out.println("受影响行数:"+result);
    }

4、修改

    @Test
    public void testUpdateById(){
        User user = new User();
        user.setId(2L);
        user.setAge(32);
        //UPDATE user SET name=?, age=? WHERE id=?
        int result = userMapper.updateById(user);
        System.out.println("受影响行数:"+result);
    }

5、查询

5.1 根据id查询用户信息
@Test
public void testSelectById(){
	//根据id查询用户信息
	//SELECT id,name,age,email FROM user WHERE id=?
	User user = userMapper.selectById(4L);
	System.out.println(user);
}
5.2 根据多个id查询多个用户信息
    @Test
    public void testSelectBatchIds() {
        //根据多个id查询多个用户信息
        //SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )
        List<Long> idList = Arrays.asList(4L, 5L);
        List<User> list = userMapper.selectBatchIds(idList)
    }
5.3 通过map条件查询用户信息
    @Test
    public void testSelectByMap(){
        //通过map条件查询用户信息
        //SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
        Map<String, Object> map = new HashMap<>();
        map.put("age", 22);
        map.put("name", "Mp02");
        List<User> list = userMapper.selectByMap(map);
        list.forEach(System.out::println);
    }
5.4 查询所有数据
    @Test
    public void testSelectList(){
        //selectList()根据MP内置的条件构造器查询一个list集合,null表示没有条件,即查询所有
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }

通过观察BaseMapper中的方法,大多方法中都有Wrapper类型的形参,此为条件构造器,可针
对于SQL语句设置不同的条件,若没有条件,则可以为该形参赋值null,即查询(删除/修改)所 有数据。

5.5 自定义mapper查询

UserMapper 中添加selectMapById方法

package com.tigerhhzz.springbootmybatisplusdemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tigerhhzz.springbootmybatisplusdemo.domain.User;
import org.springframework.stereotype.Repository;

import java.util.Map;

/**
 * @author tigerhhzz
 */
@Repository
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据id查询用户信息为map集合
     */

    Map<String,Object> selectMapById(Long id);

}

新建UserMapper.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.tigerhhzz.springbootmybatisplusdemo.mapper.UserMapper">

<!-- Map<String,Object> selectMapById(Long id);-->

    <select id="selectMapById" resultType="map">
        select id,name,age,email from user where id= #{id}
    </select>

</mapper>

测试方法:

    //自定义map查询
    @Test
    public void selectMapById(){
        //通过map条件查询用户信息
        Map<String, Object> map = userMapper.selectMapById(1L);
        System.out.println(map);
    }

结果输出:

在这里插入图片描述

6、通用Service

说明:
通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行 remove 删 除
list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆, 泛型 T 为任意实体对象 建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类

官网地址:https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3

6.1 IService

MyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl,封装了常见的业务层逻辑
详情查看源码IService和ServiceImpl

6.1.1 IService源码:
/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.extension.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * 顶级 Service
 *
 * @author hubin
 * @since 2018-06-23
 */
public interface IService<T> {

    /**
     * 插入一条记录(选择字段,策略插入)
     *
     * @param entity 实体对象
     */
    boolean save(T entity);

    /**
     * 插入(批量)
     *
     * @param entityList 实体对象集合
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean saveBatch(Collection<T> entityList) {
        return saveBatch(entityList, 1000);
    }

    /**
     * 插入(批量)
     *
     * @param entityList 实体对象集合
     * @param batchSize  插入批次数量
     */
    boolean saveBatch(Collection<T> entityList, int batchSize);

    /**
     * 批量修改插入
     *
     * @param entityList 实体对象集合
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean saveOrUpdateBatch(Collection<T> entityList) {
        return saveOrUpdateBatch(entityList, 1000);
    }

    /**
     * 批量修改插入
     *
     * @param entityList 实体对象集合
     * @param batchSize  每次的数量
     */
    boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

    /**
     * 根据 ID 删除
     *
     * @param id 主键ID
     */
    boolean removeById(Serializable id);

    /**
     * 根据 columnMap 条件,删除记录
     *
     * @param columnMap 表字段 map 对象
     */
    boolean removeByMap(Map<String, Object> columnMap);

    /**
     * 根据 entity 条件,删除记录
     *
     * @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    boolean remove(Wrapper<T> queryWrapper);

    /**
     * 删除(根据ID 批量删除)
     *
     * @param idList 主键ID列表
     */
    boolean removeByIds(Collection<? extends Serializable> idList);

    /**
     * 根据 ID 选择修改
     *
     * @param entity 实体对象
     */
    boolean updateById(T entity);

    /**
     * 根据 whereEntity 条件,更新记录
     *
     * @param entity        实体对象
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    boolean update(T entity, Wrapper<T> updateWrapper);

    /**
     * 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
     *
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    default boolean update(Wrapper<T> updateWrapper) {
        return update(null, updateWrapper);
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean updateBatchById(Collection<T> entityList) {
        return updateBatchById(entityList, 1000);
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     * @param batchSize  更新批次数量
     */
    boolean updateBatchById(Collection<T> entityList, int batchSize);

    /**
     * TableId 注解存在更新记录,否插入一条记录
     *
     * @param entity 实体对象
     */
    boolean saveOrUpdate(T entity);

    /**
     * 根据 ID 查询
     *
     * @param id 主键ID
     */
    T getById(Serializable id);

    /**
     * 查询(根据ID 批量查询)
     *
     * @param idList 主键ID列表
     */
    List<T> listByIds(Collection<? extends Serializable> idList);

    /**
     * 查询(根据 columnMap 条件)
     *
     * @param columnMap 表字段 map 对象
     */
    List<T> listByMap(Map<String, Object> columnMap);

    /**
     * 根据 Wrapper,查询一条记录 <br/>
     * <p>结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default T getOne(Wrapper<T> queryWrapper) {
        return getOne(queryWrapper, true);
    }

    /**
     * 根据 Wrapper,查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param throwEx      有多个 result 是否抛出异常
     */
    T getOne(Wrapper<T> queryWrapper, boolean throwEx);

    /**
     * 根据 Wrapper,查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    Map<String, Object> getMap(Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper,查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param mapper       转换函数
     */
    <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

    /**
     * 根据 Wrapper 条件,查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    int count(Wrapper<T> queryWrapper);

    /**
     * 查询总记录数
     *
     * @see Wrappers#emptyWrapper()
     */
    default int count() {
        return count(Wrappers.emptyWrapper());
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    List<T> list(Wrapper<T> queryWrapper);

    /**
     * 查询所有
     *
     * @see Wrappers#emptyWrapper()
     */
    default List<T> list() {
        return list(Wrappers.emptyWrapper());
    }

    /**
     * 翻页查询
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper);

    /**
     * 无条件翻页查询
     *
     * @param page 翻页对象
     * @see Wrappers#emptyWrapper()
     */
    default <E extends IPage<T>> E page(E page) {
        return page(page, Wrappers.emptyWrapper());
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);

    /**
     * 查询所有列表
     *
     * @see Wrappers#emptyWrapper()
     */
    default List<Map<String, Object>> listMaps() {
        return listMaps(Wrappers.emptyWrapper());
    }

    /**
     * 查询全部记录
     */
    default List<Object> listObjs() {
        return listObjs(Function.identity());
    }

    /**
     * 查询全部记录
     *
     * @param mapper 转换函数
     */
    default <V> List<V> listObjs(Function<? super Object, V> mapper) {
        return listObjs(Wrappers.emptyWrapper(), mapper);
    }

    /**
     * 根据 Wrapper 条件,查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default List<Object> listObjs(Wrapper<T> queryWrapper) {
        return listObjs(queryWrapper, Function.identity());
    }

    /**
     * 根据 Wrapper 条件,查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param mapper       转换函数
     */
    <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

    /**
     * 翻页查询
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper);

    /**
     * 无条件翻页查询
     *
     * @param page 翻页对象
     * @see Wrappers#emptyWrapper()
     */
    default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {
        return pageMaps(page, Wrappers.emptyWrapper());
    }

    /**
     * 获取对应 entity 的 BaseMapper
     *
     * @return BaseMapper
     */
    BaseMapper<T> getBaseMapper();

    /**
     * 以下的方法使用介绍:
     *
     * 一. 名称介绍
     * 1. 方法名带有 query 的为对数据的查询操作, 方法名带有 update 的为对数据的修改操作
     * 2. 方法名带有 lambda 的为内部方法入参 column 支持函数式的
     *
     * 二. 支持介绍
     * 1. 方法名带有 query 的支持以 {@link ChainQuery} 内部的方法名结尾进行数据查询操作
     * 2. 方法名带有 update 的支持以 {@link ChainUpdate} 内部的方法名为结尾进行数据修改操作
     *
     * 三. 使用示例,只用不带 lambda 的方法各展示一个例子,其他类推
     * 1. 根据条件获取一条数据: `query().eq("column", value).one()`
     * 2. 根据条件删除一条数据: `update().eq("column", value).remove()`
     *
     */

    /**
     * 链式查询 普通
     *
     * @return QueryWrapper 的包装类
     */
    default QueryChainWrapper<T> query() {
        return ChainWrappers.queryChain(getBaseMapper());
    }

    /**
     * 链式查询 lambda 式
     * <p>注意:不支持 Kotlin </p>
     *
     * @return LambdaQueryWrapper 的包装类
     */
    default LambdaQueryChainWrapper<T> lambdaQuery() {
        return ChainWrappers.lambdaQueryChain(getBaseMapper());
    }

    /**
     * 链式更改 普通
     *
     * @return UpdateWrapper 的包装类
     */
    default UpdateChainWrapper<T> update() {
        return ChainWrappers.updateChain(getBaseMapper());
    }

    /**
     * 链式更改 lambda 式
     * <p>注意:不支持 Kotlin </p>
     *
     * @return LambdaUpdateWrapper 的包装类
     */
    default LambdaUpdateChainWrapper<T> lambdaUpdate() {
        return ChainWrappers.lambdaUpdateChain(getBaseMapper());
    }

    /**
     * <p>
     * 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
     * 此次修改主要是减少了此项业务代码的代码量(存在性验证之后的saveOrUpdate操作)
     * </p>
     *
     * @param entity 实体对象
     */
    default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
        return update(entity, updateWrapper) || saveOrUpdate(entity);
    }
}

6.1.2 ServiceImpl源码:
/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.extension.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 , PK 是主键泛型 )
 *
 * @author hubin
 * @since 2018-06-23
 */
@SuppressWarnings("unchecked")
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {

    protected Log log = LogFactory.getLog(getClass());

    @Autowired
    protected M baseMapper;

    @Override
    public M getBaseMapper() {
        return baseMapper;
    }

    /**
     * 判断数据库操作是否成功
     *
     * @param result 数据库操作返回影响条数
     * @return boolean
     */
    protected boolean retBool(Integer result) {
        return SqlHelper.retBool(result);
    }

    protected Class<T> currentModelClass() {
        return (Class<T>) ReflectionKit.getSuperClassGenericType(getClass(), 1);
    }

    /**
     * 批量操作 SqlSession
     *
     * @deprecated 3.3.0
     */
    @Deprecated
    protected SqlSession sqlSessionBatch() {
        return SqlHelper.sqlSessionBatch(currentModelClass());
    }

    /**
     * 释放sqlSession
     *
     * @param sqlSession session
     * @deprecated 3.3.0
     */
    @Deprecated
    protected void closeSqlSession(SqlSession sqlSession) {
        SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(currentModelClass()));
    }

    /**
     * 获取 SqlStatement
     *
     * @param sqlMethod ignore
     * @return ignore
     */
    protected String sqlStatement(SqlMethod sqlMethod) {
        return SqlHelper.table(currentModelClass()).getSqlStatement(sqlMethod.getMethod());
    }

    @Override
    public boolean save(T entity) {
        return retBool(baseMapper.insert(entity));
    }

    /**
     * 批量插入
     *
     * @param entityList ignore
     * @param batchSize  ignore
     * @return ignore
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveBatch(Collection<T> entityList, int batchSize) {
        String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE);
        int size = entityList.size();
        executeBatch(sqlSession -> {
            int i = 1;
            for (T entity : entityList) {
                sqlSession.insert(sqlStatement, entity);
                if ((i % batchSize == 0) || i == size) {
                    sqlSession.flushStatements();
                }
                i++;
            }
        });
        return true;
    }

    /**
     * TableId 注解存在更新记录,否插入一条记录
     *
     * @param entity 实体对象
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveOrUpdate(T entity) {
        if (null != entity) {
            Class<?> cls = entity.getClass();
            TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
            Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
            String keyProperty = tableInfo.getKeyProperty();
            Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
            Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
            return StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal)) ? save(entity) : updateById(entity);
        }
        return false;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
        Assert.notEmpty(entityList, "error: entityList must not be empty");
        Class<?> cls = currentModelClass();
        TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
        Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
        String keyProperty = tableInfo.getKeyProperty();
        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
        int size = entityList.size();
        executeBatch(sqlSession -> {
            int i = 1;
            for (T entity : entityList) {
                Object idVal = ReflectionKit.getMethodValue(cls, entity, keyProperty);
                if (StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal))) {
                    sqlSession.insert(sqlStatement(SqlMethod.INSERT_ONE), entity);
                } else {
                    MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
                    param.put(Constants.ENTITY, entity);
                    sqlSession.update(sqlStatement(SqlMethod.UPDATE_BY_ID), param);
                }
                // 不知道以后会不会有人说更新失败了还要执行插入 😂😂😂
                if ((i % batchSize == 0) || i == size) {
                    sqlSession.flushStatements();
                }
                i++;
            }
        });
        return true;
    }

    @Override
    public boolean removeById(Serializable id) {
        return SqlHelper.retBool(baseMapper.deleteById(id));
    }

    @Override
    public boolean removeByMap(Map<String, Object> columnMap) {
        Assert.notEmpty(columnMap, "error: columnMap must not be empty");
        return SqlHelper.retBool(baseMapper.deleteByMap(columnMap));
    }

    @Override
    public boolean remove(Wrapper<T> wrapper) {
        return SqlHelper.retBool(baseMapper.delete(wrapper));
    }

    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return false;
        }
        return SqlHelper.retBool(baseMapper.deleteBatchIds(idList));
    }

    @Override
    public boolean updateById(T entity) {
        return retBool(baseMapper.updateById(entity));
    }

    @Override
    public boolean update(T entity, Wrapper<T> updateWrapper) {
        return retBool(baseMapper.update(entity, updateWrapper));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateBatchById(Collection<T> entityList, int batchSize) {
        Assert.notEmpty(entityList, "error: entityList must not be empty");
        String sqlStatement = sqlStatement(SqlMethod.UPDATE_BY_ID);
        int size = entityList.size();
        executeBatch(sqlSession -> {
            int i = 1;
            for (T anEntityList : entityList) {
                MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
                param.put(Constants.ENTITY, anEntityList);
                sqlSession.update(sqlStatement, param);
                if ((i % batchSize == 0) || i == size) {
                    sqlSession.flushStatements();
                }
                i++;
            }
        });
        return true;
    }

    @Override
    public T getById(Serializable id) {
        return baseMapper.selectById(id);
    }

    @Override
    public List<T> listByIds(Collection<? extends Serializable> idList) {
        return baseMapper.selectBatchIds(idList);
    }

    @Override
    public List<T> listByMap(Map<String, Object> columnMap) {
        return baseMapper.selectByMap(columnMap);
    }

    @Override
    public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
        if (throwEx) {
            return baseMapper.selectOne(queryWrapper);
        }
        return SqlHelper.getObject(log, baseMapper.selectList(queryWrapper));
    }

    @Override
    public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
        return SqlHelper.getObject(log, baseMapper.selectMaps(queryWrapper));
    }

    @Override
    public int count(Wrapper<T> queryWrapper) {
        return SqlHelper.retCount(baseMapper.selectCount(queryWrapper));
    }

    @Override
    public List<T> list(Wrapper<T> queryWrapper) {
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {
        return baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    public List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {
        return baseMapper.selectMaps(queryWrapper);
    }

    @Override
    public <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
        return baseMapper.selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
    }

    @Override
    public <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {
        return baseMapper.selectMapsPage(page, queryWrapper);
    }

    @Override
    public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
        return SqlHelper.getObject(log, listObjs(queryWrapper, mapper));
    }

    /**
     * 执行批量操作
     *
     * @param fun fun
     * @since 3.3.0
     */
    protected void executeBatch(Consumer<SqlSession> fun) {
        Class<T> tClass = currentModelClass();
        SqlHelper.clearCache(tClass);
        SqlSessionFactory sqlSessionFactory = SqlHelper.sqlSessionFactory(tClass);
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        try {
            fun.accept(sqlSession);
            sqlSession.commit();
        } catch (Throwable t) {
            sqlSession.rollback();
            Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
            if (unwrapped instanceof RuntimeException) {
                MyBatisExceptionTranslator myBatisExceptionTranslator
                    = new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
                throw Objects.requireNonNull(myBatisExceptionTranslator.translateExceptionIfPossible((RuntimeException) unwrapped));
            }
            throw ExceptionUtils.mpe(unwrapped);
        } finally {
            sqlSession.close();
        }
    }
}
6.2 创建Service接口和实现类

UserService

package com.tigerhhzz.springbootmybatisplusdemo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.tigerhhzz.springbootmybatisplusdemo.domain.User;

/**
 * @author tigerhhzz
 * @date 2023/5/5 10:51
 */
public interface UserService extends IService<User> {
}

UserServiceImpl

package com.tigerhhzz.springbootmybatisplusdemo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tigerhhzz.springbootmybatisplusdemo.domain.User;
import com.tigerhhzz.springbootmybatisplusdemo.mapper.UserMapper;
import com.tigerhhzz.springbootmybatisplusdemo.service.UserService;

/**
 * @author tigerhhzz
 * @date 2023/5/5 10:53
 */
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

6.3 测试查询记录数

创建测试类和测试方法

package com.tigerhhzz.springbootmybatisplusdemo;

import com.tigerhhzz.springbootmybatisplusdemo.service.UserService;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * @author tigerhhzz
 * @date 2023/5/5 11:10
 */
@SpringBootTest
@MapperScan("com.tigerhhzz.springbootmybatisplusdemo.mapper")
public class MyBatisPlusServiceTest {


    @Autowired
    UserService userService;

    @Test
    public void testGetCount(){
        long count = userService.count();
        System.out.println("总记录数:" + count);
    }
}

6.4 测试批量插入
    @Test
    public void testSaveBatch() {
        // SQL长度有限制,海量数据插入单条SQL无法实行,
        // 因此MP将批量插入放在了通用Service中实现,而不是通用Mapper
        ArrayList<User> users = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            User user = new User();
            user.setName("tiger" + i);
            user.setAge(20 + i);
            users.add(user);
        }
        //SQL:INSERT INTO t_user ( username, age ) VALUES ( ?, ? )
        userService.saveBatch(users);
    }

四、常用注解

1、@TableName

经过以上的测试,在使用MyBatis-Plus实现基本的CRUD时,我们并没有指定要操作的表,只是在
Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为user表

由此得出结论,MyBatis-Plus在确定操作的表时,由BaseMapper的泛型决定,即实体类型决
定,且默认操作的表名和实体类型的类名一致

  1. 问题
    若实体类类型的类名和要操作的表的表名不一致,会出现什么问题?
    我们将表user更名为t_user,测试查询功能
    程序抛出异常,Table ‘mybatis_plus.user’ doesn’t exist,因为现在的表名为t_user,而默认操作
    的表名和实体类型的类名一致,即user表
    在这里插入图片描述

  2. 通过@TableName解决问题

在实体类类型上添加@TableName(“t_user”),标识实体类对应的表,即可成功执行SQL语句

package com.tigerhhzz.springbootmybatisplusdemo.domain;

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

/**
 * @author tigerhhzz
 * @date 2023/5/4 16:09
 */
@Data
//设置实体类所对应的表名
@TableName("t_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;

}
  1. 通过全局配置解决问题

在开发的过程中,我们经常遇到以上的问题,即实体类所对应的表都有固定的前缀,例如t_或tbl_
此时,可以使用MyBatis-Plus提供的全局配置,为实体类所对应的表名设置默认的前缀,那么就
不需要在每个实体类上通过@TableName标识实体类对应的表

mybatis-plus:
	configuration:
		# 配置MyBatis日志
		log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
	global-config:
		db-config:
			# 配置MyBatis-Plus操作表的默认前缀
			table-prefix: t_

2、@TableId

经过以上的测试,MyBatis-Plus在实现CRUD时,会默认将id作为主键列,并在插入数据时,默认 基于雪花算法的策略生成id

  1. 问题

若实体类和表中表示主键的不是id,而是其他字段,例如uid,MyBatis-Plus会自动识别uid为主 键列吗?

我们实体类中的属性id改为uid,将表中的字段id也改为uid,测试添加功能 程序抛出异常,Field ‘uid’ doesn’t have a default value,说明MyBatis-Plus没有将uid作为主键 赋值

在这里插入图片描述

  1. 通过@TableId解决问题

在实体类中uid属性上通过@TableId将其标识为主键,即可成功执行SQL语句

package com.tigerhhzz.springbootmybatisplusdemo.domain;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author tigerhhzz
 * @date 2023/5/4 16:09
 */
@Data
//设置实体类所对应的表名
//@TableName("t_user")
public class User {

    @TableId
    private Long uid;

    private String name;

    private Integer age;

    private String email;

}
  1. @TableId的value属性

若实体类中主键对应的属性为id,而表中表示主键的字段为uid,此时若只在属性id上添加注解 @TableId,则抛出异常Unknown column ‘id’ in ‘field list’,即MyBatis-Plus仍然会将id作为表的主键操作,而表中表示主键的是字段uid 此时需要通过@TableId注解的value属性,指定表中的主键字段,@TableId(“uid”) 或者 @TableId(value=“uid”)

package com.tigerhhzz.springbootmybatisplusdemo.domain;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author tigerhhzz
 * @date 2023/5/4 16:09
 */
@Data
//设置实体类所对应的表名
//@TableName("t_user")
public class User {

    //将属性所对应的字段指定为主键
    @TableId("uid")
    private Long id;

    private String name;

    private Integer age;

    private String email;

}
  1. @TableId的type属性

type属性用来定义主键策略


/**
 * @author tigerhhzz
 * @date 2023/5/4 16:09
 */
@Data
//设置实体类所对应的表名
//@TableName("t_user")
public class User {

    //将属性所对应的字段指定为主键
    @TableId(value = "uid",type = IdType.AUTO)
    private Long id;

    private String name;

    private Integer age;

    private String email;

}

常用的主键策略:

描述
IdType.ASSIGN_ID(默认)基于雪花算法的策略生成数据id,与数据库id是否设置自增无关
IdType.AUTO使用数据库的自增策略,注意,该类型请确保数据库设置了id自增,否则无效

配置全局主键策略:

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    auto-mapping-behavior: full
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:mapper/**/*Mapper.xml
  global-config:
    #MybatisPlus的全局配置
    db-config:
      # 逻辑不删除的值
      logic-not-delete-value: 1
      # 逻辑删除
      logic-delete-value: 0
      # 配置MyBatis-Plus操作表的默认前缀
      table-prefix: t_
      # 配置MyBatis-Plus的主键策略
      id-type: auto

3、@TableField

经过以上的测试,我们可以发现,MyBatis-Plus在执行SQL语句时,要保证实体类中的属性名和 表中的字段名一致

如果实体类中的属性名和字段名不一致的情况,会出现什么问题呢?

  1. 情况1

若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格 例如实体类属性userName,表中字段user_name
此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格 相当于在MyBatis中配置

  1. 情况2

若实体类中的属性和表中的字段不满足情况1 例如实体类属性name,表中字段username
此时需要在实体类属性上使用@TableField(“username”)设置属性所对应的字段名

4、@TableLogic

4.1 逻辑删除

物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库 中仍旧能看到此条数据记录
使用场景:可以进行数据恢复

4.2 实现逻辑删除

step1:数据库中创建逻辑删除状态列,设置默认值为1

在这里插入图片描述

4.3 实体类中添加逻辑删除属性
package com.tigerhhzz.springbootmybatisplusdemo.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author tigerhhzz
 * @date 2023/5/4 16:09
 */
@Data
//设置实体类所对应的表名
//@TableName("t_user")
public class User {

    //将属性所对应的字段指定为主键
    @TableId(value = "uid",type = IdType.AUTO)
    private Long id;

    private String name;

    private Integer age;

    private String email;

    @TableLogic
    private Integer isDeleted;

}

4.4 测试

测试删除功能,真正执行的是修改

UPDATE t_user SET is_deleted=0 WHERE uid IN ( ? , ? , ? ) AND is_deleted=1 

测试查询功能,被逻辑删除的数据默认不会被查询

SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=1 

五、条件构造器和常用接口

1、wapper介绍

在这里插入图片描述

  • Wrapper : 条件构造抽象类,最顶端父类
    • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
      • QueryWrapper : 查询条件封装
      • UpdateWrapper : Update 条件封装
      • AbstractLambdaWrapper : 使用Lambda 语法
        • LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
        • LambdaUpdateWrapper : Lambda 更新封装Wrapper

2、QueryWrapper(查询和删除)

2.1、组装查询条件
package com.tigerhhzz.springbootmybatisplusdemo;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tigerhhzz.springbootmybatisplusdemo.domain.User;
import com.tigerhhzz.springbootmybatisplusdemo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

/**
 * @author tigerhhzz
 * @date 2023/5/8 14:17
 */
@SpringBootTest
@MapperScan("com.tigerhhzz.springbootmybatisplusdemo.mapper")
public class MybatisPlusWrapTest {

    @Autowired
    UserMapper userMapper;

    @Test
    public void test01(){
        //查询用户名包含m,年龄在21到23之间,邮箱不为空的用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name","m")
                .between("age",21,23)
                .isNotNull("email");

        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);

    }

}

查询结果:

SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=1 AND (name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)

在这里插入图片描述

2.2、组装排序条件
    @Test
    public void test02(){
        //查询用户,按照年龄的降序排序,若年龄相同,则按照id升序排序
        // SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=1 ORDER BY age DESC , uid ASC 
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age")
                .orderByAsc("uid");

        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);

    }

查询结果:

SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=1 ORDER BY age DESC , uid ASC

在这里插入图片描述

2.3、组装删除条件

因为添加了逻辑删除,此方法其实执行的是修改语句update

    @Test
    public void test03(){
        //删除email为空的用户
        //UPDATE t_user SET is_deleted=0 WHERE is_deleted=1 AND (email IS NULL)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        //条件构造器也可以构建删除语句的条件
        int result = userMapper.delete(queryWrapper);
        System.out.println("受影响的行数:" + result);
    }

结果:
在这里插入图片描述

2.4、条件的优先级
    @Test
    public void test04() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //将(年龄大于20并且用户名中包含有m)或邮箱为null的用户信息修改
        //UPDATE t_user SET age=?, email=? WHERE is_deleted=1 AND (name LIKE ? AND age > ? OR email IS NULL) 
        queryWrapper
                .like("name", "m")
                .gt("age", 20)
                .or()
                .isNull("email");
        User user = new User();
        user.setAge(18);
        user.setEmail("test04@baomidou.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("受影响的行数:" + result);
    }

结果:
在这里插入图片描述

    @Test
    public void test0401() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        //UPDATE t_user SET age=?, email=? WHERE is_deleted=1 AND (name LIKE ? AND ( (age > ? OR email IS NULL) )) 
        //lambda表达式内的逻辑优先运算
        queryWrapper.like("name","m")
                .and(i->i.gt("age",20).or().isNull("email"));
        User user = new User();
        user.setAge(18);
        user.setEmail("test0401@baomidou.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("受影响的行数:" + result);

    }

结果:
在这里插入图片描述

2.5、组装select子句
    @Test
    public void test05() {
        //查询用户信息的username和age字段
        //SELECT name,age FROM t_user WHERE is_deleted=1 
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("name", "age");
        //selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值为null
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        maps.forEach(System.out::println);
    }

结果:
在这里插入图片描述

2.6、实现子查询
    @Test
    public void test06() {
        //查询id小于等于6的用户信息
        //SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=1 AND (uid IN (select uid from t_user where uid <= 6)) 
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("uid", "select uid from t_user where uid <= 6");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

结果:
在这里插入图片描述

3、UpdateWrapper(修改)

    @Test
    public void test07() {
        //将(年龄大于20或邮箱为null)并且用户名中包含有m的用户信息修改
        //组装set子句以及修改条件
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        //lambda表达式内的逻辑优先运算
        updateWrapper
                .set("age", 19)
                .set("email", "test07@baomidou.com")
                .like("name", "m")
                .and(i -> i.gt("age", 20).or().isNull("email"));
        //这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null
        //UPDATE t_user SET age=?,email=? WHERE is_deleted=1 AND (name LIKE ? AND ( (age > ? OR email IS NULL) ))

        int result = userMapper.update(null, updateWrapper);
        System.out.println(result);

    }

结果:
在这里插入图片描述

4、condition

在真正开发的过程中,组装条件是常见的功能,而这些条件数据来源于用户输入,是可选的,因
此我们在组装这些条件时,必须先判断用户是否选择了这些条件,若选择则需要组装该条件,若 没有选择则一定不能组装,以免影响SQL执行的结果

思路一:

@Test
public void test08() {
//定义查询条件,有可能为null(用户未输入或未选择)
String username = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace)
构成
if(StringUtils.isNotBlank(username)){
queryWrapper.like("username","a");
}
if(ageBegin != null){
queryWrapper.ge("age", ageBegin);
}
if(ageEnd != null){
queryWrapper.le("age", ageEnd);
}
//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age >=
? AND age <= ?)
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

思路一:

上面的实现方案没有问题,但是代码比较复杂,我们可以使用带condition参数的重载方法构建查 询条件,简化代码的编写

    @Test
    public void test08UseCondition() {
        //定义查询条件,有可能为null(用户未输入或未选择)
        String username = "aaa";
        Integer ageBegin = 10;
        Integer ageEnd = 24;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace) 构成
                queryWrapper.like(StringUtils.isNotBlank(username), "name", "g")
                        .and(i->i.ge(ageBegin != null, "age", ageBegin).le(ageEnd != null, "age", ageEnd));
        //SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=1 AND (name LIKE ? AND ( (age >= ? AND age <= ?) ))
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }

结果:
在这里插入图片描述

5、LambdaQueryWrapper

    @Test
    public void test09() {
        //定义查询条件,有可能为null(用户未输入)
        String username = "g";
        Integer ageBegin = 10;
        Integer ageEnd = 24;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        //避免使用字符串表示字段,防止运行时错误
        queryWrapper
                .like(StringUtils.isNotBlank(username), User::getName, username)
                .ge(ageBegin != null, User::getAge, ageBegin)
                .le(ageEnd != null, User::getAge, ageEnd);
        //SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=1 AND (name LIKE ? AND age >= ? AND age <= ?)
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }

6、LambdaUpdateWrapper

    @Test
    public void test10() {
        //将(年龄大于20或邮箱为null)并且用户名中包含有m的用户信息修改
        //组装set子句以及修改条件
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        //lambda表达式内的逻辑优先运算
        updateWrapper
                .set(User::getAge, 19)
                .set(User::getEmail, "test10@baomidou.com")
                .like(User::getName, "m")
                .and(i -> i.gt(User::getAge, 20).or().isNull(User::getEmail));
        //这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null
        //UPDATE t_user SET age=?,email=? WHERE is_deleted=1 AND (name LIKE ? AND ( (age > ? OR email IS NULL) ))

        int result = userMapper.update(null, updateWrapper);
        System.out.println(result);

    }

结果:
在这里插入图片描述

六、插件

1、分页插件

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

1.1、添加配置类
package com.tigerhhzz.springbootmybatisplusdemo.config;

import com.baomidou.mybatisplus.annotation.DbType;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.tigerhhzz.springbootmybatisplusdemo.mapper")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}
1.2、测试
package com.tigerhhzz.springbootmybatisplusdemo;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tigerhhzz.springbootmybatisplusdemo.domain.User;
import com.tigerhhzz.springbootmybatisplusdemo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

/**
 * @author tigerhhzz
 * @date 2023/5/9 8:41
 */
@SpringBootTest
@MapperScan("com.tigerhhzz.springbootmybatisplusdemo.mapper")
public class MybatisPlusPluginTest {

    @Autowired
    UserMapper userMapper;

    @Test
    public void testPage(){
        //设置分页参数
        Page<User> page = new Page<>(2, 3);
        userMapper.selectPage(page, null);
        //获取分页数据 SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=1 LIMIT ?,?
        List<User> list = page.getRecords();
        list.forEach(System.out::println);
        System.out.println("当前页:"+page.getCurrent());
        System.out.println("每页显示的条数:"+page.getSize());
        System.out.println("总记录数:"+page.getTotal());
        System.out.println("总页数:"+page.getPages());
        System.out.println("是否有上一页:"+page.hasPrevious());
        System.out.println("是否有下一页:"+page.hasNext());
    }


}

结果:
在这里插入图片描述

2、xml自定义分页

2.1、UserMapper中定义接口方法
package com.tigerhhzz.springbootmybatisplusdemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tigerhhzz.springbootmybatisplusdemo.domain.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.Map;

/**
 * @author tigerhhzz
 */
@Repository
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据id查询用户信息为map集合
     */

    Map<String,Object> selectMapById(Long id);

    /**
     * 通过年龄查询用户信息并分页
     * @param page mybatis-plus所提供的分页对象,必须位于第一个参数的位置
     * @param age
     * @return
     */
    Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);

}
2.2、UserMapper.xml中编写SQL
<?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.tigerhhzz.springbootmybatisplusdemo.mapper.UserMapper">

<!-- Map<String,Object> selectMapById(Long id);-->

    <select id="selectMapById" resultType="map">
        select id,name,age,email from user where id= #{id}
    </select>

    <select id="selectPageVo" resultType="User">
        select uid as id,name,age,email from t_user where age > #{age}

    </select>


</mapper>
2.3、测试
    @Test
    public void testPageVo(){
        Page<User> page = new Page<>(1,3);

        Page<User> pageVo = userMapper.selectPageVo(page, 20);

        System.out.println("当前页:"+page.getCurrent());
        System.out.println("每页显示的条数:"+page.getSize());
        System.out.println("总记录数:"+page.getTotal());
        System.out.println("总页数:"+page.getPages());
        System.out.println("是否有上一页:"+page.hasPrevious());
        System.out.println("是否有下一页:"+page.hasNext());
    }

结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/504832.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MySQL】绪论 MySQL工作环境

文章目录 实验内容实验步骤实验内容 MySQL命令MySQL 的启动与关闭MySQL 管理备份和还原数据库navicat工具使用实验步骤 1. MySQL命令 (1)查看MySQL基本命令 (2)查看MySQL版本信息 2. MySQL的启动与关闭 (1)启动MySQL服务器 (2)测试服务器启动成功 (3)合法用

MATLAB绘图函数的相关介绍——海底测量、二维与三维图形绘制

系列文章目录 MATLAB求函数极限的简单介绍 文章目录 一、问题引导 1.1、海底曲线绘制问题 1.2、绘制二维与三维图形 二、代码演示 2.2、二维与三维绘图案例 2.2.1、官方对plot函数的解释 总结 一、问题引导 1.1、海底曲线绘制问题 海底测量&#xff0c;低潮时海平面上…

案例研究|萤石网络通过JumpServer解决安全运维难题

杭州萤石网络股份有限公司&#xff08;以下简称为萤石网络&#xff09;于2015年在杭州成立&#xff0c;是安全智能生活主流品牌&#xff0c;核心产品包括智能家居摄像头、智能门锁、智能服务机器人等。2021年&#xff0c;萤石网络家用摄像头占国内出货量市场份额的25%&#xff…

代码随想录算法训练营day32 | 贪心算法:122.买卖股票的最佳时机II ,55. 跳跃游戏,45.跳跃游戏II

代码随想录算法训练营day32 | 贪心算法&#xff1a;122.买卖股票的最佳时机II &#xff0c;55. 跳跃游戏&#xff0c;45.跳跃游戏II 122.买卖股票的最佳时机II55. 跳跃游戏45.跳跃游戏II 122.买卖股票的最佳时机II 教程视频&#xff1a;https://www.bilibili.com/video/BV1ev4…

Java基础(33)Java集合详解

集合类主要负责保存、盛装其他数据&#xff0c;因此集合类也被称为容器类。Java 所有的集合类都位于 java.util 包下&#xff0c;提供了一个表示和操作对象集合的统一构架&#xff0c;包含大量集合接口&#xff0c;以及这些接口的实现类和操作它们的算法。 集合类和数组不一样&…

2023年湖北安全员ABC证报考条件都有哪些?有什么区别?启程别

2023年湖北安全员ABC证报考条件都有哪些&#xff1f;有什么区别&#xff1f;启程别 一、安全员ABC证是什么&#xff1f; 安全员A、B、C证属于建筑三类人员证书。建筑三类人员&#xff1a;是指建筑施工企业主要负责人、项目负责人和专职安全生产管理人员。 建筑企业的法人代表&…

【Linux下】 线程操作及线程互斥

【Linux下】 线程操作及线程互斥 线程操作 注&#xff1a;以下函数使用时&#xff0c;编译文件时需带上-lpthread选项&#xff0c;因为下面的函数都是线程库里面的函数 pthread_self #include <pthread.h> pthread_t pthread_self(void);**作用&#xff1a;**获取当前…

淘宝天猫1688京东商品详情API接口,封装接口可高并发

要提供商品详情数据需要知道具体的商品信息&#xff0c;但通常商品详情数据应包括以下内容&#xff1a; 商品名称&#xff1a;商品的名称&#xff0c;以方便顾客对其进行识别和区分。 商品描述&#xff1a;一段让顾客能够全面认识商品的描述。应能够有效地展示商品的特性、功能…

大数据赛项|2023年广东省大学生计算机设计大赛初赛结果公示

2023年广东省大学生计算机设计大赛 暨第16届中国大学生计算机设计大赛 粤港澳大湾区赛初赛结果公示 根据《广东省教育厅关于做好2023年广东省本科高校大学生学科竞赛工作的通知》&#xff0c;广东外语外贸大学承办2023年“广东省大学生计算机设计大赛”。 在广大师生的热情…

迅为国产化RK3588开发平台16G大内存64G存储2路千兆以太网4G/5G通信

iTOP-3588开发板采用瑞芯微RK3588处理器&#xff0c;是全新一代AloT高端应用芯片采用8nmLP制程&#xff0c;搭载八核64位CPU(四核Cortex-A76四核Cortex-A55架构)集成MaliG610MP4四核GPU&#xff0c;内置AI加速器NPU&#xff0c;算力达6Tops&#xff0c;集成独立的8K视频硬件编码…

OpenCV-Python图像阈值

目录 简单阈值 自适应阈值 Otsu的二值化 所谓的图像阈值&#xff0c;就是图像二值化&#xff0c;什么是二值化&#xff0c;就是只有0和1&#xff0c;没有其他的。在OpenCV的图像里面&#xff0c;二值化表示图像的像素为0和255&#xff0c;并没有其他的值&#xff0c;它跟灰度…

js逆向-某东h5st

声明 本文仅供学习参考&#xff0c;如有侵权可私信本人删除&#xff0c;请勿用于其他途径&#xff0c;违者后果自负&#xff01; 如果觉得文章对你有所帮助&#xff0c;可以给博主点击关注和收藏哦&#xff01; 文章标题 声明前言参数分析扣代码算法还原 前言 目标网站&…

SpringCloud项目实例3--通信服务负载均衡

只是在pom.xml文件中添加了spring-cloud-starter-loadbalancer依赖并且在RestTemplate类中添加了一个LoadBalance的注解。这就是另外一种负载均衡的实现方案 Spring Cloud LoadBalancer 介绍 这种方案有什么优点呢&#xff1f; 减少整个系统的复杂度&#xff0c;不需要额外部…

BDD行为驱动开发+Python案例解析

简介&#xff1a;BDD&#xff08;Behavior-Driven Development&#xff0c;行为驱动开发&#xff09;是一种敏捷软件开发方法&#xff0c;它强调软件应该按照预期的行为来开发。BDD的核心理念是使用自然语言编写的可读性强、易于理解的用户故事&#xff08;User Stories&#x…

【前端三剑客之CSS】

目录 1.CSS1.1什么是CSS1.2 引入方式1.2.1内部样式1.2.2 行内样式表1.2.3 外部样式 2.选择器2.1 基础选择器2.1.1 标签选择器2.1.2 类选择器2.1.3 id选择器2.1.4 通配符选择器 2.2 基础选择器小结2.3 复合选择器2.3.1 后代选择器 3.元素属性3.1 字体元素3.2 文本属性3.3 背景属…

滨海县一中学被指为苏醒全国感恩教育巡回演讲营销搭台

梦想与爱同行—苏醒全国感恩教育巡回演讲活动今天下午一点半在滨海西湖路一中操场举行&#xff0c;数千学生和家长参加。 苏醒全国感恩教育巡回演讲开始&#xff0c;苏醒先生先用一口流利的英语做自我介绍&#xff0c;然后又用中文向前来参加的学生和学生家长介绍说&#xff0…

FS4055B是一款3.2V最高3.6V磷酸铁锂充电IC

FS4055B是一款3.2V最高3.6V磷酸铁锂充电IC&#xff0c;输入电源正负极反接保护的单芯片&#xff0c;兼容大小 REV_1.0 是一款完整的单节锂电池充电器&#xff0c;电池正负极反接保护、 3mA-500mA 充电电流。采用涓流、 恒流、恒压控制&#xff0c;SOT23-5 封装与较少的外部元件…

【MySqL】 表的创建,查看,删除

目录 一.使用Cmd命令执行操作 1.使用&#xff08; mysql -uroot -p)命令进入数据库 2.创建表之前先要使用数据库 3.创建表之前要先确定表的名称&#xff0c;列名&#xff0c;以及每一列的数据类型及属性 4.创建表 注意&#xff1a; 5.查看所有已创建的表 6.查看单表 …

H3C防火墙单机旁路部署(网关在防火墙)

防火墙旁路部署在核心交换机上&#xff0c;内网有三个网段vlan 10&#xff1a;172.16.10.1/24、vlan 20&#xff1a;172.16.20.1/24、vlan30&#xff1a;172.16.30.1。要求内网网关在防火墙设备上&#xff0c;由防火墙作为DHCP服务器给终端下发地址&#xff0c;同时由防火墙来控…

算法笔记Day1 | 时间复杂度和空间复杂度的七七八八

文章目录 时间空间复杂度1. 时间空间复杂度的重要性(作用)2. 时间复杂度和大O表示法1&#xff09;算法图解2&#xff09;代码随想录3&#xff09;王道《数据结构》 3. 大O指的是最糟的情形和一般的情形1&#xff09;大O表示的是一般情况&#xff0c;并不是严格的上界2&#xff…