精华内容
下载资源
问答
  • 2021-02-01 20:13:00

    这里将告诉您结合mybatis-plus 实现实体操作多表关联查询,教程操作方法:

    multipleselect

    java mybatis 实现简单多表查询

    简介

    实现简单的实体类操作多表, 首先你的项目是使用了mybatis-plus 才可以使用。

    ​ 通过解析实体,调用通用的XML来实现多表查询, 提供一个设计多表查询的思路,复杂的Sql嵌套等目前并不支持

    目前只支持:

    ​ left join方式,(能关联的两张表的实体中关联字段名称必须一样,数据库字段可以不一样可以通@TableField注解来解决

    ​ where 基本查询条件等

    ​分页 查询

    ​order 排序

    可以用来三两句搞定一些简单关联查询业务,解决不需要写的代码

    设计说明

    如何关联表?

    ​找第一张表注解为 TableId (mybatis-plus 注解)的属性名, 到每二张表找同样的属性名, 如果没找到,反过来找,如果还没找到,挨个属性找。以此类推,实现关联的前提条件是 主从表的实体关联列名必须是一样的

    // user 表

    @TableId

    private Integer userId

    // address 表

    @TableId

    private Integer addressId

    private Integer userId

    //那么自动条件为 user.user_id = address.user_id

    //或者是

    @TableId(value="id")

    private Integer userId

    // address 表

    @TableId(value="id")

    private Integer addressId

    @TableField(value="test_user_id")

    private Integer userId

    //目前只有left join

    //那么自动条件为 user.id = address.test_user_id

    使用说明

    ​将 com.freedomen.multipselect 包放到你的项目中,使 com.freedomen.multipselect.mapper里的xml 要被扫描到,或手动配置, com.freedomen.multipselect.service也要被发现

    //引入service

    @Autowired

    private MultipleService multipleService;

    //表关联, 关联用户表和地址表,查找 用户表的所有字段和地址表的所有字段

    MultipleSelect multipleSelect = MultipleSelect.newInstance("${1}", new User(), new Address());

    multipleSelect

    .where("${0}")

    .like("userName", "张三");

    multipleService.mulSelect(multipleSelect);

    查找字段

    //MultipleSelect.newInstance 的第一个参数是所要查找的字段

    //${0} 或 ${user} 表是第一张表的所有字段 ${0}.userName或${user}.userName表示userName字段, 默认第一张表的字段全部都返回的。 ${}中间的参数可以是后面实体的下标,也可以是表名 如user、user_address

    //字段中有@TableField(exist=false)注解也是被跳过的

    //下面是要订单表的所有信息 和用户的姓名与号码 和地址

    MultipleSelect.newInstance("${1}.userName,${1}.userPhone,${2}", new Orders(), new User(), new Address());

    查找条件

    eq: =

    notEq: !=

    like: LIKE (前置已经加了 '%')

    between: between

    and: 改变连接方式为 AND练级(默认)

    or: 改变 连接方式为 OR

    division:括号 ,不支持括号嵌套括号

    in: IN

    notIn: NOT IN

    notLike: NOT LIKE

    ...

    //实例好 查找实体后可以操作实体

    //注意: 如何实体内属性有值 将会以 eq方式and连接做为where 条件

    /*

    可以关联的必要条件

    Orders:

    @TableId //或者数据库字段为其它@TableId(value="id")

    private Long ordersId;

    private Long userId;

    ...

    User:

    @TableId

    private Long userId;

    ...

    Address:

    @TableId

    private Long addressId;

    private Long userId;

    ...

    */

    MultipleSelect multipleSelect = MultipleSelect.newInstance("${1}.userName,${1}.userPhone,${2}", new Orders(), new User(), new Address());

    multipleSelect

    .where("${0}") //哪张表

    .eq("ordersId", 1) //并且 订单id = 1

    .like("ordersName", "cmcc") //并且 订单名称 like ''%cmcc'

    .or() //改变后续操作关系为 OR, 默认为AND

    .notEq("orderSno", "123"); //或者 orderSno 不等于 '123'

    multipleSelect

    .where("${1}") //哪张表接着用户表 默认and连接 可以 .or()改为 OR

    .in("userId", [1, 2, 3]); // 并且userId in [1, 2, 3]

    multipleSelect

    .where("${2}")

    .or()

    .like("adressDetails", "江苏"); //或者 地址 like '江苏'

    multipleService.mulSelect(multipleSelect); //查询

    //括号

    multipleSelect.where("${0}")

    .eq("componyId", 1)

    .division()

    .like("userName", "abcd")

    .or()

    .like("userPhone", "abcd");

    // 部分sql: compony_id = 1 and (user_name = 'abcd' or user_phone = 'abcd')

    排序

    //MultipleSelect.setOrderBy(...columns)

    MultipleSelect.setOrderBy("${0}.createTime", "${1}.ordersName desc", "${2}.userId asc", ...)

    分页

    //MultipleSelect.setPage(pageNo, pageSize);

    MultipleSelect.setPage(1, 15); //第一页 每页 15条

    multipleService.mulSelect返回结果

    //MultipleResult

    /*原型

    private List> data; //结果数据

    private Integer pageNo; //如果设置了分页 会有

    private Integer pageSize; //如果设置了分页 会有

    private Integer total;//如果设置了分页 会有

    */

    逻辑删除

    //默认是读取 mybatis-plus 的 TableLogic 注解 0 未删除,

    //如果不是用 0 表示未删除, 可以修改 MultipleSelect 的 setCustomWhere 方法中的下面这段中的 0

    if (logic != null)

    sb.append(" AND ")

    .append(te.getNickName())

    .append(".")

    .append(logic)

    .append(" = ")

    .append("0");

    结合mybatis-plus 实现实体操作多表关联查询就为您介绍到这里,感谢您关注懒咪学编程c.lanmit.com.

    本文地址:https://c.lanmit.com/shujuku/qita/13784.html

    更多相关内容
  • MyBatis-Plus 删除操作

    2022-01-06 10:11:19
    删除操作 Server层、Controller层编写 package com.lmgd.mybatisplus.service.impl; import com.lmgd.mybatisplus.mapper.UserMapper; import com.lmgd.mybatisplus.pojo.User; import ...

    逻辑删除

    物理删除:从数据库中直接移除 deleted=0

    逻辑删除:在数据库中没有移除,而是通过一个变量来让他失效 deleted=1

    删除操作

    Server层、Controller层编写

    package com.lmgd.mybatisplus.service.impl;
    
    import com.lmgd.mybatisplus.mapper.UserMapper;
    import com.lmgd.mybatisplus.pojo.User;
    import com.lmgd.mybatisplus.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Author LMGD
     * @Date 2021/12/15 9:59
     */
    @Service
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public int deleteById(Long id) {
            return userMapper.deleteById(id);
        }
    
        @Override
        public int deleteByMap(Map<String, Object> map) {
            return userMapper.deleteByMap(map);
        }
    
        /**
        * 批量删除
        */
        @Override
        public int deleteBatchIds(List list) {
            return userMapper.deleteBatchIds(list);
        }
    
        /**
         * 批量删除
         *
         * @param ids
         * @return
         */
        @Override
        public int deleteBatchUserIds(String[] ids) {
            QueryWrapper wrapper = new QueryWrapper<>();
            wrapper.in("user_id", ids);
            return userMapper.delete(wrapper);
        }
    }
    
    /**
     * @Author LMGD
     * @Date 2021/12/15 10:05
     */
    @RequestMapping("/user")
    @RestController
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @RequestMapping("/deleteById")
        public BaseResponse deleteById(@RequestBody Long id) {
            return BaseResponse.returnSuccess(userService.deleteById(id));
        }
    
        @RequestMapping("/deleteByMap")
        public BaseResponse deleteByMap(@RequestBody Map<String, Object> map) {
            return BaseResponse.returnSuccess(userService.deleteByMap(map));
        }
    
        @RequestMapping("/deleteBatchIds")
        public BaseResponse deleteBatchIds(@RequestBody Integer[] ids) {
            return BaseResponse.returnSuccess(userService.deleteBatchIds(Arrays.asList(ids)));
        }
    
        @RequestMapping("/deleteBatchUserIds")
        public BaseResponse deleteBatchUserIds(@RequestBody String[] ids) {
            try {
                return BaseResponse.returnSuccess(userService.deleteBatchUserIds(ids));
            } catch (Exception e) {
                e.printStackTrace();
                return BaseResponse.returnFault(e.getMessage());
            }
        }
    }

    接口调用以及控制台日志输出

    deleteByMap 接口调用效果图

     deleteBatchIds 接口调用效果图

     deleteById 接口调用效果图

    展开全文
  • Mybatis批量删除多表

    2020-08-29 03:12:29
    MyBatis的作用我想不用多说,今天说说MyBatis中的批量删除操作。 需要的朋友一起看看吧
  • 数据基础 两张表,头行结构。逻辑结构:一对多,一个...批量删除头表,这里在每删除一条头表内容的时候,就需要相应的取删除它所对应的行表的信息。 解决方法 在controller中接收到的,是需要删除的头表的id集合id...

    数据基础

    两张表,头行结构。逻辑结构:一对多,一个老师有多个学生。为帮助理解,相当于是一张老师表一张学生表。以下代码中没有用这两张表的字段,以头表行表来替代老师表和学生表,通用性高一些。
    1541582063.jpg
    1541582063(1).jpg

    问题

    1. 批量删除行表信息,单表删除操作。
    2. 批量删除头表,这里在每删除一条头表内容的时候,就需要相应的取删除它所对应的行表的信息。

    解决方法

    1. 在controller中接收到的,是需要删除的头表的id集合ids
    @Permission(permissionLogin = true)
    @ApiOperation(value = "[删除] 批量删除以及级联删除")
    @RequestMapping(value = "/batchDelete",method = RequestMethod.DELETE)
        public ResponseEntity<Map<String,Object>> batchDelete(@RequestBody List<Long> ids) {
            return Optional.ofNullable(listService.batchDelete(ids))
                    .map(result -> new ResponseEntity<>(result, HttpStatus.OK))
                    .orElseThrow(() -> new HapException("error.listService.batchDelete"));
        }
    

    2.先进行行表的删除。

    • service实现类中,这里是级联删除的关键,
    @Override
    public Map<String, Object> batchDelete(List<Long> ids) {
            Map<String, Object> resultMap = new HashMap<>();
            int status = 0;
            //级联删除
            if (!ids.isEmpty()) {
                status = listMapper.batchDeleteCascadeList(ids);
            }
            resultMap.put("delete.one", status);
            //批量删除
            if (!ids.isEmpty()) {
                status = listMapper.batchDelete(ids);
            }
            resultMap.put("delete.list", status);
            return resultMap;
        }
    
    • 行表删除的mapper接口
        /**
         * [删除] 级联删除
         *
         * @return
         */
        int batchDeleteCascadeList(@Param(value = "idList") List<Long> idList);
    
    • 行表删除的xml,这里也是关键,删除行表中 uuid 是接收到的id集合中的项目所对应的的值,将每个头表项目所对应的行表内容删除。
     <delete id="batchDeleteCascadeList">
            DELETE FROM 
            one
            WHERE
            uuid IN
            (SELECT uuid FROM list WHERE id IN
            <foreach item="id" index="index" collection="idList" open="(" separator="," close=")">
                #{id}
            </foreach>
            )
        </delete>
    
    1. 进行头表的数据删除
    • mapper接口
        /**
         * [删除] 根据id批量删除头表信息
         *
         * @param idList
         * @return
         */
        int batchDelete(@Param(value = "idList") List<Long> idList);
    
    • xml
        <delete id="batchDelete" parameterType="java.util.List">
            delete from 
            list
            where id in
            <foreach collection="idList" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </delete>
    

    总结

    以上代码中只是截取了部分关键信息,还有一些service接口代码没有贴出来。

    这是使用java的方法拼接实现级联删除。如果有mybatis的拼接或者是其他更高效的方法,求指导!

    展开全文
  • 三款神器(MyBatis Plus + MyBatisX + MyBatis Plus Join)数据CURD代码直接生成,大大提高生产力

    大家好,我是一航!

    程序员每天的搬砖日常,可以说CURD占据了绝大部分的工作;因此,数据库的CURD也就占据了很大一部分的工作时间,不是在配置xml,就是在写sql的路上;

    那有没有什么方式能否把这份苦力活给替代了呢?当然是有的,也就是今天介绍的2框框架+1个工具(MyBatis Plus + MyBatisX + MyBatis Plus Join);不写一行数据库操作代码,不加一行配置文件;一键生成代码基础的CURD联表查询API统统搞定;让我们可以安心将精力完全放在产品业务逻辑开发上。

    开整!!!

    目录说明

    • 框架、工具介绍
    • 数据库相关配置
    • MybatisX代码自动生成
    • MyBatis Plus使用
      • 结构说明
      • Service的CURD操作
      • 条件构造器
    • MyBatis Plus Join联表查询
    • 总结

    框架、工具介绍

    • MyBatis Plus

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

      官网地址:https://mp.baomidou.com/

    • MyBatis Plus Join

      一款对MyBatis Plus 扩展的框架,在其基础上增加了联表查询相关的API;

      https://gitee.com/best_handsome/mybatis-plus-join

    • MyBatisX

      MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。用于一键生成ORM代码;该插件在本文中的主要目的是为了快速生成基于MyBatis Plus相关的代码;

    接下来就要开始对框架和工具的实战运用了;

    导入依赖

    • 必备

      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-boot-starter</artifactId>
          <version>3.4.3.4</version>
      </dependency>
      

      数据库连接依赖;大版本务必和自己的数据库版本一致

      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.46</version>
      </dependency>
      

      分页

      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-extension</artifactId>
          <version>3.4.1</version>
      </dependency>
      

      联表查询

      <!--https://gitee.com/best_handsome/mybatis-plus-join-->
      <dependency>
          <groupId>com.github.yulichang</groupId>
          <artifactId>mybatis-plus-join</artifactId>
          <version>1.1.8</version>
      </dependency>
      
    • 辅助

      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid-spring-boot-starter</artifactId>
          <version>1.1.9</version>
      </dependency>
      
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <optional>true</optional>
      </dependency>
      
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.73</version>
      </dependency>
      

    数据库配置

    • 数据库表

      一张简单的用户数据表

      CREATE TABLE `user_info`  (
        `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
        `user_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',
        `age` int(11) NULL DEFAULT NULL COMMENT '年龄',
        `source` tinyint(4) NULL DEFAULT NULL COMMENT '来源',
        PRIMARY KEY (`id`) USING BTREE,
        INDEX `source_id`(`source`) USING BTREE
      ) ENGINE = InnoDB AUTO_INCREMENT = 1008 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
      
    • SpringBoot数据库配置

      spring:
        application:
          name: ehang-mybatis-plus
        #数据库连接相关配置
        datasource:
          url: jdbc:mysql://192.168.1.237:3306/ehang?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
          username: root
          password: 123456
          #阿里巴巴的druid的mysql连接池
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: com.mysql.jdbc.Driver
      
    • 启动类配置Dao扫描

      其中basePackages路径,请根据个人的实际情况填写;

      @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
      @MapperScan(basePackages = {"com.ehang.springboot.mybatisplus.generator.**.mapper"})
      

    MybatisX

    MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。一键生成ORM代码;结合MyBatis Plus,生成的代码就已经具备了数据库增删改查的基本功能,直接去开发业务功能就好了;

    插件使用步骤如下:

    • 安装插件

      安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。

    • 配置数据源

    • 自动生成ORM代码

      • 第一步

        选中表(支持多选),右键选择“MybatisX-Generator

      • 配置基础信息

      • 属性、方法配置

      • 生成后的效果

    MyBatis Plus使用

    官网:https://mp.baomidou.com/

    官方示例:https://github.com/baomidou/mybatis-plus-samples

    结构说明

    上面介绍的工具(MyBatisX)已经帮我们基于MyBatis Plus3生成好了数据库操作的基础CURD代码,先一起来简单看一下有那些内容

    • demain

      用于接收数据库数据的Java实体类

    • UserInfoMapper.xml

      指明Java实体类与数据库表之间的映射关系

      <?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.ehang.springboot.mybatisplus.generator.user.mapper.UserInfoMapper">
      
          <resultMap id="BaseResultMap" type="com.ehang.springboot.mybatisplus.generator.user.demain.UserInfo">
                  <id property="id" column="id" jdbcType="INTEGER"/>
                  <result property="userName" column="user_name" jdbcType="VARCHAR"/>
                  <result property="age" column="age" jdbcType="INTEGER"/>
                  <result property="source" column="source" jdbcType="TINYINT"/>
          </resultMap>
      
          <sql id="Base_Column_List">
              id,user_name,age,
              source
          </sql>
      </mapper>
      
    • mapper

      数据库操作的Mapper,继承了MyBatis Plus的BaseMapper

      public interface UserInfoMapper extends BaseMapper<UserInfo> {
      }
      

      BaseMapper帮我们做了大量的数据库基础操作,详情如下:

      public interface BaseMapper<T> extends Mapper<T> {
          int insert(T entity);
      
          int deleteById(Serializable id);
      
          int deleteByMap(@Param("cm") Map<String, Object> columnMap);
      
          int delete(@Param("ew") Wrapper<T> queryWrapper);
      
          int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
      
          int updateById(@Param("et") T entity);
      
          int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
      
          T selectById(Serializable id);
      
          List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
      
          List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
      
          T selectOne(@Param("ew") Wrapper<T> queryWrapper);
      
          Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
      
          List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
      
          List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
      
          List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
      
          <E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
      
          <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
      }
      
    • Service

      service层的基础接口,继承了MyBatis Plus的IService,定义了众多基础的Service接口,由于内容较多,这里就不贴出来了,可以自行查看IService接口的定义;

      如果自动生成的接口无法满足业务需求的时候,也可以在这里定义接口,来满足个性化的需要。

      public interface UserInfoService extends IService<UserInfo> {
      }
      
    • ServiceImpl

      继承了MyBatis Plus 的ServiceImpl,ServiceImpl基于BaseMapper实现了IService定义的基础的接口

      public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
          implements UserInfoService{
      }
      

    到此,三个简单的类,CURD相关的Service层、Dao层功能就已经全部有了;如果是非特殊情况,这些API已经足够我们去做业务功能开发了。

    Service的CURD功能

    基本的结构了解清楚之后,就一起来看看,IService到底帮我们提供了那些API,这些API又要如何去使用;

    API列表

    API功能描述
    save添加、保存支持单条和批量
    saveOrUpdate添加或者修改主键不存在就添加,否则就基于主键修改
    remove删除数据条件删除、主键删除、批量删除
    update修改支持单条修改、批量修改
    get查询单条记录
    list批量查询批量查询
    page分页查询需要分页插件的支持
    count记录数查询总数、满足条件的记录数
    chain流式调用让API调用更加方便简单

    save

    插入功能

    • API列表

      // 插入一条记录(选择字段,策略插入)
      boolean save(T entity);
      // 插入(批量)
      boolean saveBatch(Collection<T> entityList);
      // 插入(批量) batchSize指明单批次最大数据量,批量插入数量较大时,推荐使用这个
      boolean saveBatch(Collection<T> entityList, int batchSize);
      
    • 代码

      // 单个插入
      @Test
      void save() {
          UserInfo userInfo = new UserInfo(null, "张三", 10, (byte) 1);
          boolean save = userInfoService.save(userInfo);
          log.info("单条添加的结果:{}", save);
      }
      
      // 批量插入
      @Test
      void saveBatch() {
          UserInfo lisi = new UserInfo(null, "李四", 10, (byte) 1);
          UserInfo wangwu = new UserInfo(null, "王五", 10, (byte) 1);
          List<UserInfo> userInfos = new ArrayList<>();
          userInfos.add(lisi);
          userInfos.add(wangwu);
          boolean saveBatch = userInfoService.saveBatch(userInfos, 10);
          log.info("批量添加的结果:{}", saveBatch);
      }
      
    • 测试结果

    SaveOrUpdate

    插入,如果数据存在则修改

    • API列表

      // 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);
      
    • 测试代码

      @Test
      void saveOrUpdate() {
          // 单个修改
          UserInfo userInfo = new UserInfo(1004, "张三(改)", 20, (byte) 1);
          boolean saveOrUpdate = userInfoService.saveOrUpdate(userInfo);
          log.info("单条插入(或修改)的结果:{}", saveOrUpdate);
      
          // 根据条件修改
          LambdaUpdateWrapper<UserInfo> updateWrapper = new LambdaUpdateWrapper<>();
          updateWrapper.eq(UserInfo::getSource, 1);
          boolean saveOrUpdateByWrapper = userInfoService.saveOrUpdate(userInfo, updateWrapper);
          log.info("单条插入(或根据条件修改)的结果:{}", saveOrUpdateByWrapper);
      
          // 批量插入
          UserInfo lisi = new UserInfo(1005, "李四(改)", 10, (byte) 1);
          UserInfo wangwu = new UserInfo(1006, "王五(改)", 10, (byte) 1);
          List<UserInfo> userInfos = new ArrayList<>();
          userInfos.add(lisi);
          userInfos.add(wangwu);
          boolean saveBatch = userInfoService.saveOrUpdateBatch(userInfos, 10);
          log.info("批量插入(或修改)的结果:{}", saveBatch);
      }
      
    • 执行结果

    remove

    删除数据

    • API列表

      // 根据 entity 条件,删除记录
      boolean remove(Wrapper<T> queryWrapper);
      // 根据 ID 删除
      boolean removeById(Serializable id);
      // 根据 columnMap 条件,删除记录
      boolean removeByMap(Map<String, Object> columnMap);
      // 删除(根据ID 批量删除)
      boolean removeByIds(Collection<? extends Serializable> idList);
      
    • 测试代码

          @Test
          void remove() {
              // 根据条件删除
              LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
              queryWrapper.eq(UserInfo::getUserName, "张三");
              boolean remove = userInfoService.remove(queryWrapper);
              log.info("根据条件删除用户数据:{}", remove);
          }
      
          @Test
          void removeById() {
              // 根据主键id删除
              boolean removeById = userInfoService.removeById(1006);
              log.info("根据主键ID删除用户数据:{}", removeById);
      
          }
      
          @Test
          void removeByMap() {
              // 根据列的值删除
              Map<String, Object> cms = new HashMap();
              cms.put("user_name", "李四");
              cms.put("source", 1);
              boolean removeByMap = userInfoService.removeByMap(cms);
      
              log.info("根据字段值删除用户数据:{}", removeByMap);
          }
      
          @Test
          void removeByIds() {
              // 根据主键id批量删除
              List<Integer> ids = Arrays.asList(new Integer[]{1004, 1005, 1006});
              boolean removeByIds = userInfoService.removeByIds(ids);
              log.info("根据主键ids批量删除用户数据:", removeByIds);
          }
      
    • 测试结果

    update

    修改数据

    • API列表

      // 根据 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);
      
    • 测试代码

      @SpringBootTest
      @Slf4j
      public class UpdateTest {
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          public void update() {
              // 不建议使用,有
              // 以下的setSql和set选一个即可,务必要设置条件 否则有全部修改的风险
              //updateWrapper.setSql("user_name = '张三'");
              LambdaUpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>()
                      .lambda()
                      .set(UserInfo::getUserName, "一行Java(改1)")
                      .eq(UserInfo::getId, 1);
              boolean update = userInfoService.update(updateWrapper);
              log.info("根据UpdateWrapper修改(不推荐使用):{}", update);
          }
      
          @Test
          public void update2() {
              // 将符合UpdateWrapper全部修改为entity的值
              LambdaUpdateWrapper<UserInfo> updateWrapper1 = new UpdateWrapper<UserInfo>()
                      .lambda()
                      .eq(UserInfo::getUserName, "一行Java(改1)");
              UserInfo wangwu = new UserInfo(1, "一行Java(改2)", 10, (byte) 1);
              boolean update = userInfoService.update(wangwu, updateWrapper1);
              log.info("根据UpdateWrapper修改为指定对象:{}", update);
          }
      
          // 根据对象ID进行修改
          @Test
          public void updateById() {
              UserInfo wangwu = new UserInfo(1, "一行Java(改2)", 10, (byte) 1);
              boolean update = userInfoService.updateById(wangwu);
              log.info("根据对象ID修改:{}", update);
          }
      
          // 根据ID批量修改数据
          @Test
          public void updateBatchById() {
              UserInfo u1 = new UserInfo(1, "一行Java 1", 10, (byte) 1);
              UserInfo u2 = new UserInfo(2, "一行Java 2", 20, (byte) 1);
              UserInfo u3 = new UserInfo(3, "一行Java 3", 30, (byte) 1);
              List<UserInfo> us = new ArrayList<>();
              us.add(u1);
              us.add(u2);
              us.add(u3);
              boolean update = userInfoService.updateBatchById(us);
              log.info("根据对象ID批量修改:{}", update);
          }
      
          // 根据ID批量修改数据,每个批次的数量由后面的batchSize指定
          @Test
          public void updateBatchById2() {
              UserInfo u1 = new UserInfo(1, "一行Java 1", 10, (byte) 1);
              UserInfo u2 = new UserInfo(2, "一行Java 2", 20, (byte) 1);
              UserInfo u3 = new UserInfo(3, "一行Java 3", 30, (byte) 1);
              List<UserInfo> us = new ArrayList<>();
              us.add(u1);
              us.add(u2);
              us.add(u3);
              boolean update = userInfoService.updateBatchById(us, 2);
              log.info("根据对象ID批量修改:{}", update);
          }
      }
      
    • 测试结果

    Get

    获取单条记录

    • API列表

      // 根据 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);
      
    • 测试代码

      @SpringBootTest
      @Slf4j
      public class GetTest {
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void getById() {
              UserInfo userInfo = userInfoService.getById(1);
              log.info("根据ID查询用户信息:{}", userInfo);
          }
      
          // 查询一条数据,如果根据条件查询出了多条,则会报错
          @Test
          void getOne() {
              LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new QueryWrapper<UserInfo>()
                      .lambda()
                      .eq(UserInfo::getId, 1);
              UserInfo userInfo = userInfoService.getOne(lambdaQueryWrapper);
              log.info("根据ID查询单用户信息:{}", userInfo);
          }
      
          // 查询单条数据,如果返回多条数据则去取第一条返回
          @Test
          void getOne2() {
              LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new QueryWrapper<UserInfo>()
                      .lambda()
                      .eq(UserInfo::getUserName, "一行Java 1")
                      .orderByDesc(UserInfo::getId);
              UserInfo userInfo = userInfoService.getOne(lambdaQueryWrapper, false);
              log.info("根据ID查询单用户信息:{}", userInfo);
          }
      
          // 查询单条数据 以Map的方式返回
          @Test
          void getMap() {
              LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new QueryWrapper<UserInfo>()
                      .lambda()
                      .eq(UserInfo::getId, 1);
              // String为数据库列名  Object为值
              Map<String, Object> map = userInfoService.getMap(lambdaQueryWrapper);
              log.info("根据ID查询单用户信息:{}", map);
          }
      
          // 查询返回结果的第一列
          @Test
          void getObj() {
              LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new QueryWrapper<UserInfo>()
                      .lambda()
                      .eq(UserInfo::getUserName, "一行Java 1")
                      .select(UserInfo::getUserName);
      
              String obj = userInfoService.getObj(lambdaQueryWrapper, (u) -> u.toString());
              log.info("getObj:{}", obj);
          }
      }
      

      执行结果

    List

    批量查询

    • API列表

      // 查询所有
      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);
      
    • 测试代码

      package com.ehang.springboot.mybatisplus;
      
      import com.alibaba.fastjson.JSON;
      import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
      import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
      import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
      import com.ehang.springboot.mybatisplus.generator.user.demain.UserInfo;
      import com.ehang.springboot.mybatisplus.generator.user.service.UserInfoService;
      import lombok.extern.slf4j.Slf4j;
      import org.junit.jupiter.api.Test;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.test.context.SpringBootTest;
      
      import java.util.Map;
      
      @SpringBootTest
      @Slf4j
      public class PageTest {
      
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void page() {
              // 分页查询;结果以对象方式返回
              Page<UserInfo> page = userInfoService.page(new Page<UserInfo>(2, 5));
              log.info("page:{}", page);
          }
      
          @Test
          void pageByWrapper() {
              // 带查询条件的分页查询; 结果以对象方式返回
              // 查询条件是id大于10
              LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new QueryWrapper<UserInfo>()
                      .lambda()
                      .ge(UserInfo::getId, 10);
              Page<UserInfo> page = userInfoService.page(new Page<UserInfo>(2, 5), lambdaQueryWrapper);
              log.info(":{}", page);
          }
      
          @Test
          void pageMaps() {
              // 分页查询;以Map的方式返回
              Page<Map<String, Object>> page = userInfoService.pageMaps(new Page(2, 5));
              log.info("pageMaps:{}", JSON.toJSONString(page));
          }
      
          @Test
          void pageMapsByWrapper() {
              // 带查询条件的分页查询,结果以Map方式返回
              // 查询条件是id大于10
              LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new QueryWrapper<UserInfo>()
                      .lambda()
                      .ge(UserInfo::getId, 10);
              Page<Map<String, Object>> page = userInfoService.pageMaps(new Page(2, 5), lambdaQueryWrapper);
              log.info("pageMapsByWrapper:{}", JSON.toJSONString(page));
          }
      }
      

      执行结果

    page

    分页查询

    • 分页插件

      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-extension</artifactId>
          <version>3.4.1</version>
      </dependency>
      
    • 分页插件配置

          // 新版
          @Bean
          public MybatisPlusInterceptor mybatisPlusInterceptor() {
              MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
              interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
              return interceptor;
          }
      
      //    // 旧版
      //    @Bean
      //    public PaginationInterceptor paginationInterceptor() {
      //        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
      //        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
      //        // paginationInterceptor.setOverflow(false);
      //        // 设置最大单页限制数量,默认 500 条,-1 不受限制
      //        // paginationInterceptor.setLimit(500);
      //        // 开启 count 的 join 优化,只针对部分 left join
      //        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
      //        return paginationInterceptor;
      //    }
      
    • API列表

      // 无条件分页查询
      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);
      
    • 测试代码

      @SpringBootTest
      @Slf4j
      public class PageTest {
      
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void page() {
              // 分页查询;结果以对象方式返回
              Page<UserInfo> page = userInfoService.page(new Page<UserInfo>(2, 5));
              log.info("page:{}", page);
          }
      
          @Test
          void pageByWrapper() {
              // 带查询条件的分页查询; 结果以对象方式返回
              // 查询条件是id大于10
              LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new QueryWrapper<UserInfo>()
                      .lambda()
                      .ge(UserInfo::getId, 10);
              Page<UserInfo> page = userInfoService.page(new Page<UserInfo>(2, 5), lambdaQueryWrapper);
              log.info("pageByWrapper:{}", page);
          }
      
          @Test
          void pageMaps() {
              // 分页查询;以Map的方式返回
              Page<Map<String, Object>> page = userInfoService.pageMaps(new Page(2, 5));
              log.info("pageMaps:{}", JSON.toJSONString(page));
          }
      
          @Test
          void pageMapsByWrapper() {
              // 带查询条件的分页查询,结果以Map方式返回
              // 查询条件是id大于10
              LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new QueryWrapper<UserInfo>()
                      .lambda()
                      .ge(UserInfo::getId, 10);
              Page<Map<String, Object>> page = userInfoService.pageMaps(new Page(2, 5), lambdaQueryWrapper);
              log.info("pageMapsByWrapper:{}", JSON.toJSONString(page));
          }
      }
      

    Count

    查询记录数

    • API列表

      // 查询总记录数
      int count();
      // 根据 Wrapper 条件,查询总记录数
      int count(Wrapper<T> queryWrapper);
      
    • 测试代码

      @SpringBootTest
      @Slf4j
      public class CountTest {
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void count() {
              int count = userInfoService.count();
              log.info("总数:{}", count);
          }
      
          @Test
          void countByWrapper() {
              int count = userInfoService.count(new QueryWrapper<UserInfo>()
                      .lambda()
                      .ge(UserInfo::getId, 100));
              log.info("按条件查询总数:{}", count);
          }
      }
      

    Chain(重要)

    service的链式操作,这个是实际使用中会用的比较频繁的API,让我们在写代码时,调用API的操作更加的优雅;

    • API列表

      // 链式查询 普通
      QueryChainWrapper<T> query();
      // 链式查询 lambda 式。注意:不支持 Kotlin
      LambdaQueryChainWrapper<T> lambdaQuery(); 
      
      // 链式更改 普通
      UpdateChainWrapper<T> update();
      // 链式更改 lambda 式。注意:不支持 Kotlin 
      LambdaUpdateChainWrapper<T> lambdaUpdate();
      
    • 测试代码

      @SpringBootTest
      @Slf4j
      public class ChainTest {
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void chainQuery() {
              List<UserInfo> userInfos = userInfoService
                      .query()
                      .eq("user_name", "一行Java 1")
                      .list();
              log.info("流式查询:{}", JSON.toJSONString(userInfos));
          }
      
          @Test
          void chainLambdaQuery() {
              List<UserInfo> userInfos = userInfoService
                      .lambdaQuery()
                      .eq(UserInfo::getUserName, "一行Java 1")
                      .list();
              log.info("流式查询:{}", JSON.toJSONString(userInfos));
          }
      }
      

    Service相关的API基本已经演示完毕了,在示例代码中,也见到了一些常用的条件构造器,比如eqge等,但条件构造器远不止这么一点点;MyBatis Plus 给所有的条件构造都提供了详细的API支持

    条件构造器

    构造器详细列表

    下面通过一张表格,来完整的看一下所有条件构造器的方法;

    关键字作用示例等价SQL
    allEq匹配所有字段全部eq.query().allEq({id:1,user_name:“老王”,age:null}).list()WHERE id =1 AND user_neme=“老王” AND age IS NULL
    eq等于(==).lambdaQuery().eq(UserInfo::getId, 1)WHERE id = 1
    ne不等于(<>).lambdaQuery().ne( UserInfo::getId, 1)WHERE id <> 1
    gt大于(>).lambdaQuery().gt( UserInfo::getId, 1)WHERE id > 1
    ge大于等于(>=).lambdaQuery().ge( UserInfo::getId, 1)WHERE id >= 1
    lt小于(<).lambdaQuery().lt( UserInfo::getId, 1)WHERE id < 1
    le小于等于(<=).lambdaQuery().le( UserInfo::getId, 1)WHERE id <= 1
    between指定区间内.lambdaQuery().between( UserInfo::getId, 1,10)WHERE (id BETWEEN 1 AND 10)
    notBetween指定区间外.lambdaQuery().notBetween( UserInfo::getId, 5,100)WHERE (id NOT BETWEEN 5 AND 100)
    like字符串匹配.lambdaQuery().like( UserInfo::getUserName, “一行Java”)WHERE (user_name LIKE “%一行Java%”)
    notLike字符串不匹配.lambdaQuery().notLike( UserInfo::getUserName, “一行Java”)WHERE (user_name NOT LIKE “%一行Java%”)
    likeLeft字符串左匹配.lambdaQuery().likeLeft( UserInfo::getUserName, “一行Java”)WHERE (user_name LIKE “%一行Java”)
    likeRight字符串右匹配.lambdaQuery().likeRight( UserInfo::getUserName, “一行Java”)WHERE (user_name LIKE “一行Java%”)
    isNull等于null.lambdaQuery().isNull(UserInfo::getUserName)WHERE (user_name IS NULL)
    isNotNull不等于null.lambdaQuery().isNotNull( UserInfo::getUserName)WHERE (user_name IS NOT NULL)
    in包含.lambdaQuery().in(UserInfo::getId, 1, 2, 3)WHERE (id IN (1, 2, 3))
    notIn不包含.lambdaQuery().notIn(UserInfo::getId, 1, 2, 3)WHERE (id NOT IN (1, 2, 3))
    inSqlsql方式包含.lambdaQuery().inSql(UserInfo::getId, “1, 2, 3”)WHERE (id IN (1, 2, 3))
    notInSqlsql方式不包含.lambdaQuery().notInSql(UserInfo::getId, “1, 2, 3”)WHERE (id NOT IN (1, 2, 3))
    groupBy分组.select(“source,count(id) as sum”).groupBy(“source”).having(“count(id) > {0}”, 35);GROUP BY source HAVING count(id) > 35
    orderByAsc升序.lambdaQuery().orderByAsc(UserInfo::getSource)ORDER BY source ASC
    orderByDesc降序.lambdaQuery().orderByDesc(UserInfo::getSource)ORDER BY source DESC
    orderBy排序.lambdaQuery().orderBy(true, true, UserInfo::getSource)ORDER BY source ASC
    havinghaving子句.select(“source,count(id) as sum”).groupBy(“source”).having(“count(id) > {0}”, 35);GROUP BY source HAVING count(id) > 35
    func自定义Consumer.lambdaQuery().func(i -> {if (true) {i.eq(UserInfo::getId, 10);} else {i.eq(UserInfo::getId, 100); }})WHERE (id = 10)
    or多条件满足一个.lambdaQuery()…le(UserInfo::getId, 10) .or(i -> .eq(UserInfo::getUserName, “张三”).ge(UserInfo::getId, 1005))WHERE (id <= 10 OR (user_name = “张三” AND id >= 1005))
    and多条件同时满足.lambdaQuery().le(UserInfo::getId, 10) .and(i -> i.eq(UserInfo::getUserName, “一行Java 1”))WHERE (id <= 10 AND (user_name = “一行Java 1”))
    nested指定条件用()嵌套.lambdaQuery().ge(UserInfo::getId, 10).nested(i -> i.eq(UserInfo::getUserName, “张三”).or(m -> m.ge(UserInfo::getId, 1005)))WHERE (id >= 10 AND (user_name = “张三” OR (id >= 1005)))
    apply拼接sql.lambdaQuery().apply(“id < {0}”, 20)WHERE (id < 20)
    last拼接语句在sql最后.lambdaQuery().apply(“id < {0}”, 20).last(“limit 1”)WHERE (id < ?) limit 1
    exists子句存在数据.lambdaQuery().exists(“select id from user_info where id > 1000”)WHERE (EXISTS (select id from user_info where id > 1000))
    notExists子句不存在数据.lambdaQuery().notExists(“select id from user_info where id > 10000”)WHERE (NOT EXISTS (select id from user_info where id > 10000))

    通过上面的表格,再结合示例代码以及等价SQL就能很清晰的看出各个条件构造器的功能了;

    下面拧几个不好理解或者需要注意的构造器,专门说一下

    allEq

    • 参数

      • condition

        所有条件是否生效,默认是true;设置为false之后,设置的所有的条件都不会生效

      • params

        Map参数;设置需要匹配的字段和对应的值

      • filter

        用于设置需要过滤的字段

      • null2IsNull

        是否忽略null值;默认是true,如果有需要匹配的字段是null,则会添加 is null的查询条件;如果设置为false,将会自动剔除所有值null的字段校验

    • 测试代码

      /**
       * AllEq
       */
      @SpringBootTest
      @Slf4j
      public class AllEqTest {
          @Autowired
          UserInfoService userInfoService;
      
          Map<String, Object> params = new HashMap();
      
          @BeforeEach
          public void init() {
              params.put("user_name", "一行Java 1");
              params.put("id", null);
          }
      
          @Test
          void allEq() {
              List<UserInfo> list = userInfoService.query().allEq(params).list();
              log.info("{}", JSON.toJSONString(list));
              // 等价sql: SELECT id,user_name,age,source FROM user_info WHERE (user_name = "一行Java 1" AND id IS NULL)
          }
      
          @Test
          void allEqConditionFalse() {
              //-----------condition参数------------
              // 表示是否才上查询条件,如果等于false 将不会添加任何查询条件
              List<UserInfo> list = userInfoService.query().allEq(false, params, true).list();
              log.info("{}", JSON.toJSONString(list));
              // 等价sql: SELECT id,user_name,age,source FROM user_info
          }
      
          @Test
          void allEqNull2IsNull() {
              //-----------null2IsNull演示------------
              // null2IsNull = false;会自动踢出null值条件
              List<UserInfo> list = userInfoService.query().allEq(params, false).list();
              // 等价sql: SELECT id,user_name,age,source FROM user_info WHERE (user_name = "一行Java 1")
              log.info("{}", JSON.toJSONString(list));
          }
      
          @Test
          void allEqFilter() {
              //---------filter延时----------
              // filter字段,表示要忽略的字段
              // 以下是忽略key为id的条件
              List<UserInfo> list = userInfoService.query().allEq((k, v) -> !k.equals("id"), params).list();
              // 等价sql:SELECT id,user_name,age,source FROM user_info WHERE (user_name = "一行Java 1")
              log.info("{}", JSON.toJSONString(list));
          }
      }
      

    groupBy and having

    跟组跟having筛选

    • 示例代码

      @SpringBootTest
      @Slf4j
      public class GroupByAndHavingTest {
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void groupByAndHaving() {
              QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
              userInfoQueryWrapper.select("source,count(id) as sum")
                      .groupBy("source")
                      .having("count(id) > {0}", 35);
              List<Map<String, Object>> maps = userInfoService.listMaps(userInfoQueryWrapper);
      
              // 等价sql:SELECT source,count(id) as sum FROM user_info GROUP BY source HAVING count(id) > 35
          }
      }
      

    func

    用于设置条件子句

    实际的业务场景下,可能存在不同的业务条件下导致的sql执行条件也有所不同;那么就可以通过func子句来进行设置

    • 测试代码

      @SpringBootTest
      @Slf4j
      public class FuncTest {
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void func() {
              Boolean condition = true;
              List<UserInfo> userInfos = userInfoService.lambdaQuery()
                      .func(i -> {
                          if (condition) {
                              i.eq(UserInfo::getId, 10);
                          } else {
                              i.eq(UserInfo::getId, 100);
                          }
                      }).list();
              log.info("userInfos:{}", userInfos);
              //func(i -> {if (true) {i.eq(UserInfo::getId, 10);} else {i.eq(UserInfo::getId, 100); }})
          }
      }
      
    • 执行结果

      • Boolean condition = true;

      • Boolean condition = false;

    or 、 and

    or:多条件满足一个即可

    and:多条件同时满足

    • 示例代码

      @SpringBootTest
      @Slf4j
      public class OrAndTest {
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void or() {
              List<UserInfo> userInfos = userInfoService.lambdaQuery()
                      .le(UserInfo::getId, 10)
                      .or(i -> i.eq(UserInfo::getUserName, "张三").ge(UserInfo::getId, 1005))
                      .list();
              log.info("userInfo:{}", userInfos);
              // 等价sql:SELECT id,user_name,age,source FROM user_info WHERE (id <= 10 OR (user_name = "张三" AND id >= 1005))
          }
      
          @Test
          void and() {
              List<UserInfo> userInfos = userInfoService.lambdaQuery()
                      .le(UserInfo::getId, 10)
                      .and(i -> i.eq(UserInfo::getUserName, "一行Java 1")).list();
              log.info("userInfo:{}", userInfos);
              // 等价sql:SELECT id,user_name,age,source FROM user_info WHERE (id <= 10 AND (user_name = "一行Java 1"))
          }
      }
      
      • or

      • and

    nested、apply、last

    • nested

      嵌套;

      比如当条件中存在and和or组合的时候,就需要对or的多个条件进行嵌套,防止与and之间产生错误的组合关系

    • apply

      拼接sql;有些特殊个性化场景下,很难用api去定义一些操作;比如,需要对时间继续格式化之后作为查询条件,此时就需要借助一段简单的sql拼接来完成效果

      apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")`--->`date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
      
    • last

      在sql的末尾带上指定的语句;比如last("limit 1"),就会在sql语句的末尾加上limit 1

    • API列表

      // nested
      nested(Consumer<Param> consumer)
      nested(boolean condition, Consumer<Param> consumer)
      
      // apply
      apply(String applySql, Object... params)
      apply(boolean condition, String applySql, Object... params)
      
      // last
      last(String lastSql)
      last(boolean condition, String lastSql)
      
    • 示例代码

      @SpringBootTest
      @Slf4j
      public class Nested_Apply_Limit_Test {
          @Autowired
          UserInfoService userInfoService;
      
          @Test
          void nested() {
              List<UserInfo> userInfos = userInfoService.lambdaQuery()
                      .ge(UserInfo::getId, 10)
                      .nested(
                              i -> i.eq(UserInfo::getUserName, "张三").or(m -> m.ge(UserInfo::getId, 1005))
                      )
                      .list();
              log.info("userInfo:{}", userInfos);
              // 等价sql:SELECT id,user_name,age,source FROM user_info WHERE (id <= 10 OR (user_name = "张三" AND id >= 1005))
          }
      
          @Test
          void apply() {
              List<UserInfo> userInfos = userInfoService.lambdaQuery()
                      .apply("id < {0}", 20)
                      .list();
              log.info("userInfo:{}", userInfos);
              // 等价sql:SELECT id,user_name,age,source FROM user_info WHERE (id < 20)
          }
      
          @Test
          void last() {
              List<UserInfo> userInfos = userInfoService.lambdaQuery()
                      .last("limit 1")
                      .list();
              log.info("userInfo:{}", userInfos);
              // 等价sql:SELECT id,user_name,age,source FROM user_info limit 1
          }
      }
      

    有了这些API条件构造器,是不是一行数据库操作的代码都没有写,基础的CURD统统都能搞定了;

    但是,实际的业务并不只是基础的CURD,有没有发现,联表查询MyBatis Plus并没有支持,但是关联查询在业务开发中,又会经常用到,如果单纯基于MyBatis Plus,要实现联表,就只能自己写配置,写SQL去实现了,这就违背了本文的初衷了;

    那有没有一款框架能帮助我们去封装联表查询呢?那就是下面要介绍的一款框架MyBatis Plus Join

    MyBatis Plus Join

    MyBatis Plus Join一款专门解决MyBatis Plus 关联查询问题的扩展框架,他并不一款全新的框架,而是基于MyBatis Plus功能的增强,所以MyBatis Plus的所有功能MyBatis Plus Join同样拥有;框架的使用方式和MyBatis Plus一样简单,几行代码就能实现联表查询的功能

    官方仓库:https://gitee.com/best_handsome/mybatis-plus-join

    准备工作

    为了方便做联表测试,这里预先准备三张表(学校表、班级表、学生表),用来做关联查询,sql如下:

    DROP TABLE IF EXISTS `school_info`;
    CREATE TABLE `school_info`  (
      `id` int(11) NOT NULL,
      `school_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '学校名称',
      `school_addr` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '学校地址',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
    
    INSERT INTO `school_info` VALUES (1, 'XXX小学', 'xx区xx街道80号');
    
    -- ----------------------------------------------------------------
    
    CREATE TABLE `class_info`  (
      `id` int(11) NOT NULL,
      `class_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
      `class_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述',
      `school_id` int(11) NOT NULL COMMENT '隶属的学校',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
    
    INSERT INTO `class_info` VALUES (1, '一年级1班', NULL, 1);
    INSERT INTO `class_info` VALUES (2, '一年级2班', NULL, 1);
    
    -- ----------------------------------------------------------------
    
    CREATE TABLE `student_info`  (
      `id` int(11) NOT NULL,
      `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
      `age` int(11) NULL DEFAULT NULL,
      `class_id` int(11) NULL DEFAULT NULL,
      `school_id` int(11) NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
    
    INSERT INTO `student_info` VALUES (1, '张三', 7, 1, 1);
    INSERT INTO `student_info` VALUES (2, '李四', 7, 2, 1);
    INSERT INTO `student_info` VALUES (3, '王五', 8, 1, 1);
    INSERT INTO `student_info` VALUES (4, '赵六', 8, 1, 1);
    

    基础MyBatis Plus代码生成

    参考MyBatisX的插件使用,这里就不重复了

    MyBatis Plus Join 核心类说明

    • MPJBaseMapper

      扩展了MyBatis Plus的 BaseMapper 接口

      public interface MPJBaseMapper<T> extends BaseMapper<T> {
          Integer selectJoinCount(@Param("ew") MPJBaseJoin var1);
      
          <DTO> DTO selectJoinOne(@Param("resultTypeClass_Eg1sG") Class<DTO> var1, @Param("ew") MPJBaseJoin var2);
      
          Map<String, Object> selectJoinMap(@Param("ew") MPJBaseJoin var1);
      
          <DTO> List<DTO> selectJoinList(@Param("resultTypeClass_Eg1sG") Class<DTO> var1, @Param("ew") MPJBaseJoin var2);
      
          List<Map<String, Object>> selectJoinMaps(@Param("ew") MPJBaseJoin var1);
      
          <DTO, P extends IPage<?>> IPage<DTO> selectJoinPage(P var1, @Param("resultTypeClass_Eg1sG") Class<DTO> var2, @Param("ew") MPJBaseJoin var3);
      
          <P extends IPage<?>> IPage<Map<String, Object>> selectJoinMapsPage(P var1, @Param("ew") MPJBaseJoin var2);
      }
      
    • MPJBaseService

      扩展了MyBatis Plus的 IService 接口

      public interface MPJBaseService<T> extends IService<T> {
          Integer selectJoinCount(MPJBaseJoin var1);
      
          <DTO> DTO selectJoinOne(Class<DTO> var1, MPJBaseJoin var2);
      
          <DTO> List<DTO> selectJoinList(Class<DTO> var1, MPJBaseJoin var2);
      
          <DTO, P extends IPage<?>> IPage<DTO> selectJoinListPage(P var1, Class<DTO> var2, MPJBaseJoin var3);
      
          Map<String, Object> selectJoinMap(MPJBaseJoin var1);
      
          List<Map<String, Object>> selectJoinMaps(MPJBaseJoin var1);
      
          <P extends IPage<Map<String, Object>>> IPage<Map<String, Object>> selectJoinMapsPage(P var1, MPJBaseJoin var2);
      }
      
    • MPJBaseServiceImpl

      扩展了MyBatis Plus的 ServiceImpl 接口实现

      public class MPJBaseServiceImpl<M extends MPJBaseMapper<T>, T> extends ServiceImpl<M, T> implements MPJBaseService<T> {
      ...
      }
      

    基础代码调整

    简单的三处调整,就能完成整合工作

    • 将mapper改为继承MPJBaseMapper (必选)

      修改前

      public interface StudentInfoMapper extends BaseMapper<StudentInfo> {
      }
      

      修改后

      public interface StudentInfoMapper extends MPJBaseMapper<StudentInfo> {
      }
      
    • 将service改为继承MPJBaseService (可选)

      修改前

      public interface StudentInfoService extends BaseService<StudentInfo> {
      }
      

      修改后

      public interface StudentInfoService extends MPJBaseService<StudentInfo> {
      }
      
    • 将serviceImpl改为继承MPJBaseServiceImpl (可选)

      修改前

      @Service
      public class StudentInfoServiceImpl extends BaseServiceImpl<StudentInfoMapper, StudentInfo>
          implements StudentInfoService{
      }
      

      修改后

      @Service
      public class StudentInfoServiceImpl extends MPJBaseServiceImpl<StudentInfoMapper, StudentInfo>
          implements StudentInfoService{
      }
      

    联表测试

    测试需求:查询学生所处的班级及学校

    DTO定义

    用于联表查询后接收数据的实体类

    @Data
    public class StudentInfoDTO {
    	// 学生id
        private Integer id;
    
        // 性名
        private String name;
    
        // 年龄
        private Integer age;
    
        // 班级名称
        private String className;
    
        // 学校名称
        private String schoolName;
    
        // 学校地址 用于测试别名
        private String scAddr;
    }
    

    单记录联表查询

    @Autowired
    StudentInfoService sutdentInfoService;
    
    /**
     * 联表查询单个
     */
    @Test
    public void selectJoinOne() {
        StudentInfoDTO studentInfoDTO = sutdentInfoService.selectJoinOne(StudentInfoDTO.class,
                new MPJLambdaWrapper<StudentInfo>()
                        .selectAll(StudentInfo.class)
                        .select(SchoolInfo::getSchoolName)
                        .selectAs(SchoolInfo::getSchoolAddr, StudentInfoDTO::getScAddr)
                        .select(ClassInfo::getClassName)
                        .leftJoin(SchoolInfo.class, SchoolInfo::getId, StudentInfo::getSchoolId)
                        .leftJoin(ClassInfo.class, ClassInfo::getId, StudentInfo::getClassId)
                        .eq(StudentInfo::getId, 1));
        log.info("selectJoinOne:{}", JSON.toJSONString(studentInfoDTO));
    }
    

    简单说明

    • StudentInfoDTO.class

      表示resultType,用于接收联表查询之后的数据库返回

    • selectAll

      指明查询实体对应的所有字段

    • select

      指定查询列,同一个select只能指明单个表的列,所以多表关联时需要使用多个select去指明不同表的列

    • selectAs

      重命名,表现在sql层面是会给字段加上as(别名);主要用在数据库字段名也实体对象的名称不一致的情况;

    • leftJoin、rightJoin、innerJoin

      左链接、右连接、等值连接;不懂这三种连接方式的,可参考:SQL中 inner join、left join、right join、full join 到底怎么选?详解来了

      • 参数一:参与联表的对象
      • 参数二:on关联的指定,此属性必须是第一个对象中的值
      • 参数三:参与连表的ON的另一个实体类属性
    • 条件构造器

      联表后可能会存在各种筛选条件,可以根据上面对条件构造器的介绍,指明所需要的筛选条件,比如上面.eq(StudentInfo::getId, 1)),就是用来指明ID为1的学生信息。

    • 表名

      默认主表别名是t,其他的表别名以先后调用的顺序使用t1,t2,t3…

      需要直接apply语句的时候,就得知道对应的表面是什么再进行添加,所以不到万不得已的时候,不建议直接追加语句。

    等价SQL

    SELECT 
    	t.id,
    	t.name,
    	t.age,
    	t.class_id,
    	t.school_id,
    	t1.school_name,
    	t1.school_addr AS scAddr,
    	t2.class_name
    FROM 
    	student_info t
    	LEFT JOIN school_info t1 ON (t1.id = t.school_id)
    	LEFT JOIN class_info t2 ON (t2.id = t.class_id)
    WHERE (t.id = ?)
    

    执行结果

    联表查多条

    @Autowired
    StudentInfoService sutdentInfoService;
    
    /**
     * 联表查询批量
     */
    @Test
    public void selectJoinList() {
        List<StudentInfoDTO> studentInfoDTOS = sutdentInfoService.selectJoinList(StudentInfoDTO.class,
                new MPJLambdaWrapper<StudentInfo>()
                        .selectAll(StudentInfo.class)
                        .select(SchoolInfo::getSchoolName)
                        .selectAs(SchoolInfo::getSchoolAddr, StudentInfoDTO::getScAddr)
                        .select(ClassInfo::getClassName)
                        .leftJoin(SchoolInfo.class, SchoolInfo::getId, StudentInfo::getSchoolId)
                        .leftJoin(ClassInfo.class, ClassInfo::getId, StudentInfo::getClassId)
                //.eq(StudentInfo::getId, 1)
        );
        log.info("selectJoinList:{}", JSON.toJSONString(studentInfoDTOS));
    }
    

    等价SQL

    SELECT 
    	t.id,
    	t.name,
    	t.age,
    	t.class_id,
    	t.school_id,
    	t1.school_name,
    	t1.school_addr AS scAddr,
    	t2.class_name
    FROM 
    	student_info t
    	LEFT JOIN school_info t1 ON (t1.id = t.school_id)
    	LEFT JOIN class_info t2 ON (t2.id = t.class_id)
    

    执行结果

    联表分页查询

    @Autowired
    StudentInfoService sutdentInfoService;
    
    /**
     * 分页查询
     */
    @Test
    public void selectJoinPage() {
        IPage<StudentInfoDTO> studentInfoDTOIPage = sutdentInfoService.selectJoinListPage(new Page<>(1, 2), StudentInfoDTO.class,
                new MPJLambdaWrapper<StudentInfo>()
                        .selectAll(StudentInfo.class)
                        .select(SchoolInfo::getSchoolName)
                        .selectAs(SchoolInfo::getSchoolAddr, StudentInfoDTO::getScAddr)
                        .select(ClassInfo::getClassName)
                        .leftJoin(SchoolInfo.class, SchoolInfo::getId, StudentInfo::getSchoolId)
                        .leftJoin(ClassInfo.class, ClassInfo::getId, StudentInfo::getClassId)
                        .orderByAsc(StudentInfo::getId)
        );
        log.info("selectJoinPage:{}", JSON.toJSONString(studentInfoDTOIPage));
    }
    

    等价SQL

    SELECT 
    	t.id,
    	t.name,
    	t.age,
    	t.class_id,
    	t.school_id,
    	t1.school_name,
    	t1.school_addr AS scAddr,
    	t2.class_name
    FROM 
    	student_info t
    	LEFT JOIN school_info t1 ON (t1.id = t.school_id)
    	LEFT JOIN class_info t2 ON (t2.id = t.class_id)
    ORDER BY 
    	t.id ASC 
    LIMIT 2
    

    执行结果

    总结

    好了,MyBatis Plus + MyBatisX + MyBatis Plus Join的详细使用教程就讲解完了;再回头看,是不是发现业务功能开发一下子变的简单多了;

    本文也只是介绍了大部分常用的内容,并没有列举出两款框架的所有东西;知道怎么使用之后,更多的使用细节,可以结合API文档以及各种条件构造器,灵活变通,即可完成各种想要的效果;

    码字不易,如果觉得好用,帮忙点个赞,点个再看呗!感激涕零…

    展开全文
  • 批量删除
  • Mybatis关联映射 Mybatis关联映射的用途: 在实际的开发过程中,对于数据库的操作除了单表外往往会涉及到多张表,这些操作在面向对象中就涉及到了对象与对象之间的关联关系。针对多表之间的操作,MyBatis提供了...
  • MyBatis-PlusMyBatis的基础上只做增强,不做改变,目的是为了简化开发,提高效率。本专栏文章围绕MyBatis-Plus的常用技术点,分别演示了下面这些技术点: 《MyBatis-Plus入门案例:查询数据库中所有记录》 文章...
  • Mybatis-Plus增强包 简介 本框架(Gitee地址 )结合公司日常业务场景,对Mybatis-Plus 做了进一步的拓展封装,即保留MP原功能,又添加更多有用便捷的功能。具体拓展体现在数据自动填充(类似JPA中的审计)、关联查询...
  • 前言 背景 在 SpringBoot 项目开发前,...mapper,对数据库进行数据持久化操作,它的方法语句是直接针对数据库操作的,主要实现一些增删改查操作,在 mybatis 中方法主要与与 xxx.xml 内相互一一映射; service,业务
  • 基于Mybatis-Plus封装的多表关联查询器,优雅且美好 github地址:https://github.com/SuyunGit/mybatis-plus-join gitee地址:https://gitee.com/suyungit/mybatis-plus-join 为了解决简单的多表查询而生,避免...
  • mybatis介绍,缓存,延迟加载,mybatis是怎么和数据库交互的,重载 常见面试题 mybatis-plus,nacos配置,使用,常用实体类注解
  • 背景使用mybatis-plus单表操作十分方便,但是多表联合查询感觉又回归到xml时代了,我个人比较喜欢注解的方式,但是xml要更灵活问题点:多表多条件联合查询时间段查询分页查询springboot配置文件需要注意的是...
  • 学习并使用mybatis-plus的一些高级功能的用法例如: AR模式、 乐观锁 、逻辑删除 、自动填充、数据保护等功能 为了方便演示,咱们还是新建一个全新的项目 引入mp依赖 <dependency> <groupId>...
  • MyBatis Plus 核心功能篇

    2021-06-22 19:27:28
    本文介绍Mybatis Plus的核心功能,主要有代码生成器的使用,CRUD接口的简单介绍,条件构造器介绍,分页插件介绍和简单使用等,希望对大家有所帮助。
  • 一篇搞定MyBatis Plus

    2020-05-25 15:43:31
    什么是MyBatis Plus 国产的开源框架,基于 MyBatis 核心功能就是简化 MyBatis 的开发,提高效率 有了他甚至不用自己写sql语句了 快速上手 创建Spring Boot项目,并且在pom.xml中导入MyBatis Plus的依赖 <...
  • 物理删除:真实删除,将数据从数据库中删除删除后查询不到被删除的数据 ...2.有关联数据,不便删除 # mysql //测试逻辑删除 status int null default null # 实体类 //实现逻辑删除 @TableL.
  • JPA,Hibernate,mybatis,mybatis plus,Querydsl,JDBC五种数据库框架使用感受感受对比JPA,Hibernatejdbcmybatis,mybatis plusQuerydsl结束语 感受对比 JPA,Hibernate JPA和Hibernate之间的关系,可以简单的理解为JPA...
  • mybatis-plus二级缓存扩展理解核心要点1核心要点2 pommybatis-plus代码生成器一级缓存步骤如下:配置二级缓存(redis方式)主启动类:redis序列化和CacheManagerservice层使用参考 理解 一级缓存是SqlSession级别的...
  • MyBatis-Plus——超详细讲解配置文件

    千次阅读 多人点赞 2022-01-18 16:06:09
    超详细讲解MyBatis-Plus中的配置,对各个属性进行介绍以及演示如何使用,让我们在开发当中快人一步。
  • Springboot集成Mybatis Plus插件

    千次阅读 2019-03-24 17:08:50
    Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 官方网站:http://mp.baomidou.com Mybatis-PlusMybatis的增强工具包,其简化了CRUD操作...
  • Mybatis-Plus升级完成! 我的系统到底更新了什么?Mybatis-PlusMybatis好在了哪里? 拖拖沓沓写了将近一个月的系统,总的来说是把自己的Mybatis升级成了Mybatis-Plus,可是仔细一想又不完全是这样,还有许多细小...
  • Mybatis plus入门使用

    2021-03-28 14:26:18
    MyBatis Plus 一、快速入门 国产的开源框架,基于 MyBatis 核心功能就是简化 MyBatis 的开发,提高效率。 MyBatis Plus 快速上手 Spring Boot(2.4.4) + MyBatis Plus(国产的开源框架,并没有接入到 Spring 官方孵化...
  • mybatis plus 学习

    万次阅读 多人点赞 2017-12-05 00:49:33
    简介Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 我们的愿景是成为Mybatis最好的搭档,就像 Contra Game 中的1P、2P,基友搭配,效率翻倍...
  • 文章目录一、环境搭建二、 一、环境搭建 文件目录结构,一直截图不利于排版,请将后面代码片段对应此图建立 ... create database `mybatis_plus_test`; #指定数据库为 use `mybatis_plus_test`; drop ta...
  • MyBatis-Plus详解

    2021-05-23 13:59:30
    MyBatis-Plus   1.简介   1.1 操作步骤   1.2 mybatis-plus mapper编写规则 2.注解介绍   2.1 常用注解   2.2 mybatis-plus通用Mapper接口 3.条件构造器 4.高级查询   4.1 列投影 select   4.2 ...
  • 从前慢- Mybatis-Plus

    千次阅读 2021-01-20 22:15:40
    mybatis-plus-boot-starter 3.2.0 在入口类加入注解 @SpringBootApplication @MapperScan(“com.baizhi.dao”) public class MybatisApplication { public static void main(String[] args) { SpringApplication...
  • mybatis-plus使用

    2021-11-21 20:06:00
    Mybatis-plus开发 快速入门 1、创建数据库、数据表 CREATE DATABASE mybatis_plus; DROP TABLE IF EXISTS user; CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,476
精华内容 990
关键字:

mybatis plus 关联删除