MyBatisPlus实现复杂查询

940 阅读5分钟

MyBatisPlus实现复杂查询

MybatisPlus YAML配置

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.lqf</groupId>
    <artifactId>springboot-mybatis-plus-genrator</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>springboot-mybatis-plus-genrator</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--lombok用来简化实体类-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

mybatis-plus.properties展示(自动生成的位置做成了配置)

#此处为本项目src所在路径(代码生成器输出路径)
OutputDir=D:/V/springboot-mybatis-plus-genrator/src/main/java
#mapper.xml的生成位置
OutputDirXml=D:/V/springboot-mybatis-plus-genrator/src/main/resources
#数据库表名(此处切不可为空,如果为空,则默认读取数据库的所有表名)
tableName=fy_currency_log
#装代码的文件夹名
className=crm
#设置作者
author=lqf
#正常情况下,下面的代码无需修改!!!!!!!!!!
#自定义包路径
parent=com.lqf.springbootmybatisplusgenrator
#数据库地址
url=jdbc:mysql://******:3306/crm?useUnicode=true&characterEncoding=utf-8&tinyInt1isBit=false
userName=***
password=***

代码生成器的java类

package com.lqf.springbootmybatisplusgenrator;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
/**
 * <p>
 *     代码生成器
 * </p>
 */
public class MpGenerator {
    public static void main(String[] args) throws InterruptedException {
        //用来获取Mybatis-Plus.properties文件的配置信息
        final ResourceBundle rb = ResourceBundle.getBundle("mybatis-plus");
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(rb.getString("OutputDir"));
        gc.setOpen(false);
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(true);
        gc.setAuthor(rb.getString("author"));
        gc.setMapperName("%sMapper");
        gc.setXmlName("%sMapper");
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setControllerName("%sController");
        mpg.setGlobalConfig(gc);
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setUrl(rb.getString("url"));
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername(rb.getString("userName"));
        dsc.setPassword(rb.getString("password"));
        mpg.setDataSource(dsc);
        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent(rb.getString("parent"));
        pc.setController("controller." + rb.getString("className"));
        pc.setService("service." + rb.getString("className"));
        pc.setServiceImpl("service." + rb.getString("className") + ".impl");
        pc.setEntity("bean." + rb.getString("className"));
        pc.setMapper("dao." + rb.getString("className"));
        mpg.setPackageInfo(pc);
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return rb.getString("OutputDirXml") + "/mapper/" + rb.getString("className") + "/" + tableInfo.getEntityName() + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        mpg.setTemplate(new TemplateConfig().setXml(null));
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setInclude(new String[]{rb.getString("tableName")});
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
}

Wrapper的常用方法:

eq方法,名称是equals的缩写,两个参数,一个是数据库表字段的名称,一个是表字段值

userQueryWrapper.eq("user_id", 9); // WHERE user_id = ?

between方法,即SQL的 WHERE xxxxx字段 BETWEEN 值1 AND 值2

注意,值1一定是小于值2的

userQueryWrapper.between("xxx表字段", 10, 65); // WHERE xx字段 BETWEEN1 AND2

大于小于、大于等于、小于等于

     userQueryWrapper.gt("xx字段", 20); // WHERE columnX > valueX
        userQueryWrapper.lt("xx字段", 20); // WHERE columnX < valueX
        userQueryWrapper.ge("xx字段", 20); // WHERE columnX >= valueX
        userQueryWrapper.le("xx字段", 20); // WHERE columnX <= valueX

按字段排序:

可以是默认和N个字段,默认排序就表示ASC顺序从小到大

也可以指定排序方式,和自定的字段:

img

众多条件需要进行连接,无非就是AND & OR两种

一般只需要连续引用就表示这些一连串的条件是AND拼接,其中一个条件是可选的,就使用or方法处理

// WHERE xx字段 <= 20 AND columnX > valueX OR xxx表字段 BETWEEN 10 AND 65
userQueryWrapper.le("xx字段", 20).gt("columnX","valueX").or().between("xxx表字段", 10, 65);

1. wapper介绍

  • Wrapper : 条件构造抽象类,最顶端父类。

  • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件。

  • QueryWrapper :Entity 对象封装操作类,不是用lambda语法

  • UpdateWrapper : Update 条件封装,用于Entity对象更新操作。

  • AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。

  • LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper

  • LambdaUpdateWrapper : Lambda 更新封装Wrapper

    /**

    • ge 大于等于

    • gt 大于

    • le 小于等于

    • lt 小于

    • isNull 是null

    • isNotNull 不是nul

    • 执行的也是逻辑删除 */ @Test public void testDelete() { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.isNull("create_time").ge("age", 21).isNotNull("email");

      int result = userMapper.delete(queryWrapper); System.out.println("result = " + result); } /**

    • selectOne返回的是一条实体记录,当出现多条时会报错

    • eq 等于

    • ne 不等于 */ @Test public void testSelectOne(){ QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name","Sandy");

      User user = userMapper.selectOne(queryWrapper); System.out.println("user = " + user); } public void testSelectCount(){ QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.between("age",22,30); Integer count = userMapper.selectCount(queryWrapper); System.out.println("count = " + count); } /**

    • like

    • notLike

    • likeLeft

    • likeRight */ @Test public void testSelectMaps(){ QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.like("name","2");

      List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper); maps.forEach(System.out::println); }

in、notIn:
​
inSql、notinSql:可以实现子查询
​
例: inSql("age", "1,2,3,4,5,6")—>age in (1,2,3,4,5,6)
例: inSql("id", "select id from table where id < 3")—>id in (select id from table where id < 3)
   /**
     * orderBy
     * orderByDesc 降序
     * orderBYAsc  升序
     */
    @Test
    public void testSelectListOrderBy(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }
​
直接拼接到 sql 的最后
注意:只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用。
@Test
public void testSelectListLast() {
​
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.last("limit 1");
​
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}
​

指定要查询的列

   @Test
    public void testSelectListColumn(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        
        queryWrapper.select("id","name","age");
        
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }
​
@Test
public void testUpdateSet() {
​
    //修改值
    User user = new User();
    user.setAge(99);
​
    //修改条件
    UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
    userUpdateWrapper
        .like("name", "h")
        .set("name", "老李头")//除了可以查询还可以使用set设置修改的字段
        .setSql(" email = '123@qq.com'");//可以有子查询
​
    int result = userMapper.update(user, userUpdateWrapper);
}
​

在这里插入图片描述

分页查询全部记录

    Page<User> page = new Page<>(1, 5);
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    IPage<User> userIPage = mapper.selectPage(page, queryWrapper);
    System.out.println(userIPage);
    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录(并翻页)
     * </p>
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类
     * 和上个分页同理只是返回类型不同
     */
    @Test
    public void selectMapsPage() {
        Page<User> page = new Page<>(1, 5);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
​
        IPage<Map<String, Object>> mapIPage = mapper.selectMapsPage(page, queryWrapper);
        System.out.println(mapIPage);
    }   

条件修改

    /**
     * <p>
     * 根据 whereEntity 条件,更新记录
     * </p>
     *
     * @param entity        实体对象 (set 条件值,不能为 null)
     * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
     */
    @Test
    public void update() {
        //修改值
        User user = new User();
        user.setStatus(true);
        user.setName("zhangsan");
        //修改条件s
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        userUpdateWrapper.eq("name", "lqf");
        int update = mapper.update(user, userUpdateWrapper);
        System.out.println(update);
    }

查询总记录数

     /**
     * <p>
     * 根据 Wrapper 条件,查询总记录数
     * </p>
     *
     * @param queryWrapper 实体对象
     */
    @Test
    public void selectCount() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", "lqf");

        Integer count = mapper.selectCount(queryWrapper);
        System.out.println(count);
    }

根据entity条件,查询一条数据(selectone是返回一条数据,当出现多条时会报错)

根据entity条件 ,删除记录

VO:View Object,视图层,其作用是将指定页面的展示数据封装起来,通常用于业务层之间的数据传递。

类似于将前端页面传输的数据在后端service层封装成一个VO类,控制层需要调用时,直接调用该类中的属性,以获取各种数据:

vo, 是controller和视图层(view)打交道,要和页面中的数据结构相同更方便。dto是service层与mappe层 数据持久层交互的。

Java8 Lambda表达式迭代输出:list.forEach(x -> {System.out.println("lambda迭代:"+x);});

假设你用name来区分人,class为Student,其实就是 list.stream() .collect( Collectors.groupingBy( Student::getName, Collectors.collectingAndThen( Collectors.toList(), x - { x.stream() .collect(Collectors.maxBy(Comparator.comparing(Student::getScore))) .ifPresent(m - m.setType(1)); return x; } ) ) );

for循环快捷键---> iter

左边是参数、后边是方法体

BigDecimal做减法计算

案例中用户的金额字段使用BigDecimal作为类型,直接使用减号"-"计算两个数值的值,报错了。

仔细想想BigDecimal是一个类,也不是基本数据类型,本来就不能用减号

BigDecimal本身提供了加减乘除的方法

加法 add()函数 减法subtract()函数 乘法multipy()函数 除法divide()函数 绝对值abs()函数

将list中元素按指定字段作为组进行统计

案例:有个ArrayList list1,demo类中有属性id和price两个,需要将相同id的price求和 代码:

复制代码

Map<String, ArrayList<demo>> collect = list1.stream().collect(Collectors.groupingBy(e -> e.getId()));
collect.forEach((k,val)->{
System.out.println(k);
DoubleSummaryStatistics collect1 = val.stream().collect(Collectors.summarizingDouble(e -> e.getPrice().doubleValue())); //这里因为price是BigDecimal因此需要转换
System.out.println(collect1.getSum());
});

复制代码

collect1.getSum()就是统计的值,可以根据需要整合到自己的结果集中

type-aliases-package的作用

mapper.xml文件中resultMap的type或者parameterType会使用自定义的pojo,

此时可以用完全限定名来指定这些POJO的引用,例如

又或者你可以通过在application.properties中指定POJO扫描包来让mybatis自动扫描到自定义POJO,如下:

mybatis.type-aliases-package=com.e3mall.cms.dao.mapper

mybatis中mapper传多个入参

使用@Param

复制代码

#mapper中接口的签名
List<TbItem> selectByPage(@Param("page") int page , @Param("rows") int rows);

#sql
<select id="selectByPage" resultMap="BaseResultMap">
    SELECT
    <include refid="Base_Column_List" />
    from tb_item LIMIT #{page} , #{rows}
  </select>

复制代码

@mapper个人理解

@mapper的作用是可以给mapper接口自动生成一个实现类,让spring对mapper接口的bean进行管理,并且可以省略去写复杂的xml文件

此处借用一段代码

/UserDAO
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import entity.User;

/**
 * 添加了@Mapper注解之后这个接口在编译时会生成相应的实现类
 * 
 * 需要注意的是:这个接口中不可以定义同名的方法,因为会生成相同的id
 * 也就是说这个接口是不支持重载的
 */
@Mapper
public interface UserDAO {

    @Select("select * from user where name = #{name}")
    public User find(String name);

    @Select("select * from user where name = #{name} and pwd = #{pwd}")
    /**
      * 对于多个参数来说,每个参数之前都要加上@Param注解,
      * 要不然会找不到对应的参数进而报错
      */
    public User login(@Param("name")String name, @Param("pwd")String pwd);
}

复制代码

不过进过自己测试,用过写了xml,使用@mapper也会走到xml文件中,但是如果xml和@select同时存在,会报错,只能使用其中一种

原因:

springboot默认不会扫描到对应的bean文件

解决:

方式1、在mapper接口上添加@Mapper

方式2、在application启动类上添加@MapperScan(basePackages = {"com.e3mall.cms.dao.mapper"})

IDEA快捷键

Ctrl + Shift + Enter自动结束代码,行末自动添加分号 (必备)
Ctrl + Shift + /注释代码块
Ctrl+/注释代码
Ctrl+展开代码
Ctrl+y反撤回
Ctrl+z撤回
Ctrl-折叠代码
Ctrl + Shift + U对选中的代码进行大 / 小写轮流转换 (必备)