Mybatis Plus

前言

在java中访问数据库,使用jdbc

  1. 项目中直接使用jdbc,访问数据库。创建Connection,ResultSet。
  2. 把jdbc的操作进行了封装。创建了很多工具类,比如DBUtil。
  3. 持久层的框架
    1. hibernate:全自动的ORM框架。实现了java object – 表的映射。可以通过java对象的方法,操作表中的数据。开发人员可以不了解或少了解sql语言。
      可以使用hibernate访问不同的数据库,不需要改变代码。通用不同的数据库。
    2. jpa规范:定义了访问数据库的各种操作。定义了一致的方法操作数据库。
      jpa有各种实现:hibernate,open-jpa,link
    3. mybatis:需要编写xml配置文件,在xml文件中编写sql语句,访问数据库。任何的操作需要使用xml文件。对开发人员要求比较高:需要熟悉sql语言。单表的CRUD也需要使用xml文件,编写sql语句。
    4. mybatis plus:简称MP。对mybaits的增强。在mybaits之外加入了一层,通过mybatis plus实现单表的CRUD,不使用xml文件。分页,性能统计,逻辑删除等等。

持久层框架中mybaits应用比较多,而且比重在逐渐的上升。通常项目的组合是SSM。mybaits之所以火,是因为他的灵活,使用方便,优化比较容易。

mybaits的直接执行sql语句,sql语句是写在xml文件中,使用mybatis需要多个xml配置文件,在一定程度上比较繁琐。一般数据库的操作都要涉及到CURD。

mybatis-plus是在mybaits上的增强,减少了xml的配置,几乎不用编写xml就可以做到单表的CURD,极大的提高了开发的效率。

什么是Mybatis-plus

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

Mybatis-plus在Mybatis之上套了一层外衣,单表CURD的操作几乎都可以由Mybatis-plus代替执行。而且提供了各种查询方式,分页行为。作为使用者无需编写xml,直接调用Mybatis-plus提供的API就可以了。

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

快速开始

几分钟就可以上手 MP,前提是需要熟悉 mybatis,spring 或 spring boot, maven,
掌握 lambda 表达式更能提升效率。
准备环境:
⚫ 拥有 Java 开发环境以及相应 IDE
⚫ 熟悉 Spring Boot
⚫ 熟悉 Maven
课堂的开发环境:IntelliJ IDEA 2018 Ultimate , MySQL 5.7 , Maven 3 , Spring Boot 2.x。

准备数据表

现有一张 User 表,其表结构如下:

idnameageemail
1Jone18test1@baomidou.com
2Jack20test2@baomidou.com
3Tom28test3@baomidou.com
4Sandy21test4@baomidou.com
5Billie24test5@baomidou.com

其对应的数据库 Schema 脚本如下:

DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);

其对应的数据库 Data 脚本如下:

DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

项目搭建

  • 使用Spring Initializr快速初始化一个Spring Boot工程

在这里插入图片描述

  • 导入maven依赖

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.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.qin</groupId>
    <artifactId>mp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mp</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
<!--        mybatis plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</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>
  • 配置数据库连接配置

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mp?userUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456

编码

  • 编写实体类 User.java
package com.qin.mp.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;

//实体类
public class User {
    //定义属性: 属性名和表中的列名一样
    /**
     * 指定主键的方式----@TableId
     * value:主键字段的名称,如果是id,可以不用写
     * type:指定主键的类型,主键的值如何生成。 idType.AUTO 表示自动增长
     */
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String name;
    private String email;
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}
  • 编写Mapper类 UserMapper.java
package com.qin.mp.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qin.mp.entity.User;

/**
 * 自定义Mapper,就是Dao接口
 * 1. 要实现BaseMapper
 * 2. 指定实体类
 *
 * BaseMapper是MP框架中的对象,定义了17个操作方法(CRUD)
 */
public interface UserMapper extends BaseMapper<User> {
}
  • 添加@MapperScan扫描Mapper文件夹
package com.qin.mp;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @MapperScan:扫描器,指定Mapper类所在的包
 */
@SpringBootApplication
@MapperScan(value = "com.qin.mp.mapper")
public class MpApplication {
    public static void main(String[] args) {
        SpringApplication.run(MpApplication.class, args);
    }
}

测试

在test包下进行测试

package com.qin.mp;

import com.qin.mp.entity.User;
import com.qin.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

//镇压警告
//@SuppressWarnings("all")
@SpringBootTest
class MpApplicationTests {

    //使用自动注入,注入Mapper对象
    //项目没有启动时,容器中没有UserMapper的bean,所以会报错
    @Autowired
    private UserMapper userMapper;

    //定义测试方法
    //测试添加操作: insert
    @Test
    public void testInsert(){
        //创建user对象
        User user = new User("jack", "934@qq.com", 21);
        //调用UserMapper的方法,也就是父接口BaseMapper中提供的方法
        int rows = userMapper.insert(user);
        System.out.println("insert 的结果"+rows);
    }
}
/*
insert 的结果1
*/

开启日志

application.yml

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

再次测试结果:

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@36c2b646] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1872034717 wrapping com.mysql.cj.jdbc.ConnectionImpl@17fa1336] will not be managed by Spring
==>  Preparing: INSERT INTO user ( name, email, age ) VALUES ( ?, ?, ? ) 
==> Parameters: java(String), 934@qq.com(String), 21(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@36c2b646]
insert 的结果1

CRUD

CRUD的操作是来自BaseMapper中的方法。BaseMapper中共有17个方法

CRUD操作都有多个不同参数的方法。继承BaseMapper其中的方法

在这里插入图片描述

Insert

insert()返回值int,数据插入成功的行数,成功的记录数。

如果主键是自增的,user对象的id也会被赋值

@Test
public void testInsert(){
    //创建user对象
    User user = new User("java", "934@qq.com", 21);
    //调用UserMapper的方法,也就是父接口BaseMapper中提供的方法
    int rows = userMapper.insert(user);
    System.out.println("insert 的结果"+rows);
    System.out.println("id:"+user.getId());
}
/*
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5a6fa56e] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1444642131 wrapping com.mysql.cj.jdbc.ConnectionImpl@1cc680e] will not be managed by Spring
==>  Preparing: INSERT INTO user ( name, email, age ) VALUES ( ?, ?, ? ) 
==> Parameters: java(String), 934@qq.com(String), 21(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5a6fa56e]
insert 的结果1
id:3
*/

update

updateById(User)这个方法传入的参数是修改后的实体类,这个对象的id属性不能为空

其余非空属性修改到数据库中

判断字段是否要修改,加入到set语句,是根据属性值是否为null

注意:如果有些属性为基础类型(int),其默认值不为null,如果没有设置值,也会修改数据库中的字段

实体类属性推荐使用包装类

/**
     * 更新操作update
     */
@Test
public void testUpdateUser(){
    User user = new User();
    user.setName("修改的数据");
    user.setAge(22);
    user.setEmail("edit@163.com");
    user.setId(2);
    //执行更新,根据主键值更新
    /*UPDATE user SET name=?, email=?, age=? WHERE id=?
         *更新了所有非null属性值, 条件where id = 主键值
         */
    int rows = userDao.updateById(user);
    System.out.println("update rows:"+rows);
}

/**
     * 控制更新的属性
     */
@Test
public void testUpdateUser2(){
    User user  = new User();
    user.setId(2);
    user.setName("zhangsan");
    //更新数据
    //UPDATE user SET name=? WHERE id=?
    int i = userDao.updateById(user);
    System.out.println("i:"+i);

}

/**
     * 更新数据: 实体类的属性是基本类型 - int age
     */
@Test
public void testUpdateUser3(){
    User user  = new User();
    user.setId(3);
    user.setEmail("lisi@sina.com");
    //实体对象 user: [name = null , email = "lisi@sina.com" , age = 0  ]
    //没有修改 name ,age
    //判断字段是否要修改, 加入到set语句, 是根据属性值是否为null .
    //UPDATE user SET email=?, age=? WHERE id=?
    int rows = userDao.updateById(user);
    System.out.println("rows:"+rows);

}

delete

删除有多个方法

  • deleteById:按主键删除,删除一条数据
  • deleteByMap:根据Map中条件删除,删除一条数据
  • deleteBatchIds:批量删除,可删除多条数据
/**
 * 按主键删除一条数据
 * 方法是deleteById()
 * 参数:主键值
 * 返回值:是删除的成功记录数
 */
@Test
public void testDeleteById(){

    //DELETE FROM user WHERE id=?
    int rows  = userDao.deleteById(3);
    System.out.println("deleteById:"+rows);
}
/**
 * 按条件删除数据, 条件是封装到Map对象中
 * 方法:deleteByMap(map对象);
 * 返回值:删除成功的记录数
 */
@Test
public void testDeleteByMap(){
    //创建Map对象,保存条件值
    Map<String,Object> map  = new HashMap<>();
    //put("表的字段名",条件值) , 可以封装多个条件
    map.put("name","zs");
    map.put("age",20);
    //调用删除方法
    //DELETE FROM user WHERE name = ? AND age = ?
    int rows = userDao.deleteByMap(map);
    System.out.println("deleteByMap rows:"+rows);


}
/**
 * 批处理方式:使用多个主键值,删除数据
 * 方法名称:deleteBatchIds()
 * 参数: Collection<? extends Serializable> var1
 * 返回值:删除的记录数
 */
@Test
public void deleteByBatchId(){
   /* List<Integer> ids  = new ArrayList<>();
    ids.add(1);
    ids.add(2);
    ids.add(3);
    ids.add(4);
    ids.add(5);*/

    //使用lambda创建List集合
    List<Integer> ids = Stream.of(1, 2, 3, 4, 5).collect(Collectors.toList());
    //删除操作
    //DELETE FROM user WHERE id IN ( ? , ? , ? , ? , ? )
    int i = userDao.deleteBatchIds(ids);
    System.out.println("deleteBatchIds:"+i);
}

select

  • 根据id主键查询
  • 批量查询记录
  • 使用Map的条件查询
/**
 * 实现查询 selectById ,根据主键值查询
 * 参数:主键值:
 * 返回值: 实体对象(唯一的一个对象)
 */
@Test
public void testSelectById(){
    /**
     * 生成的sql: SELECT id,name,email,age FROM user WHERE id=?
     * 如果根据主键没有查找到数据, 得到的返回值是 null
     */
    User user = userDao.selectById(6);
    System.out.println("selectById:"+user);

    //在使用对象之前,需要判断对象是否为null
    if(user != null){
        //业务方法的调用
    }


}

/**
 * 实现批处理查询,根据多个主键值查询, 获取到List
 * 方法:selectBatchIds
 * 参数:id的集合
 * 返回值:List<T>
 */
@Test
public void testSelectBatchId(){
    List<Integer> ids = new ArrayList<>();
    ids.add(6);
    ids.add(9);
    ids.add(10);

    //查询数据
    //SELECT id,name,email,age FROM user WHERE id IN ( ? , ? , ? )
    List<User> users = userDao.selectBatchIds(ids);
    System.out.println("size:"+users.size());
    for (User u:users){
        System.out.println("查询的用户:"+u);
    }
}

/**
 * 使用lambda查询数据
 */
@Test
public void testSelectBatchId2(){
    List<Integer> ids = Stream.of(6, 9, 10, 15).collect(Collectors.toList());
    //SELECT id,name,email,age FROM user WHERE id IN ( ? , ? , ? , ? )
    List<User> users = userDao.selectBatchIds(ids);
    //遍历集合
    users.forEach( u -> {
        System.out.println("查询的user对象:"+u);
    });
}

/**
 * 使用Map做多条件查询
 * 方法:selectByMap()
 * 参数:Map<String,Object>
 * 返回值:List<T>
 *
 */
@Test
public void testSelectMap(){
    //创建Map,封装查询条件
    Map<String,Object> map = new HashMap<>();
    //key是字段名, value:字段值 ,多个key,是and 联接
    map.put("name","zhangsan");
    map.put("age",20);

    //根据Map查询
    //SELECT id,name,email,age FROM user WHERE name = ? AND age = ?
    List<User> users = userDao.selectByMap(map);
    users.forEach(user -> {
        System.out.println("selectByMap:"+user);
    });
}

ActiveRecord(AR)

概述

  • 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field
  • ActiveRecord负责把自己持久化。在ActiveRecord中封装了对数据库的访问,通过对象自己实现CRUD,实现优雅的数据库操作。
  • ActiveRecord也封装了部分业务逻辑。可以作为业务对象使用。

准备数据表

Create Table

CREATE TABLE `dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `mobile` varchar(30) DEFAULT NULL,
  `manager` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

AR实体类

必须继承Model,Model定义了表的CRUD方法,Dept属性名和列名是一样的.

package com.wkcto.plus.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.activerecord.Model;

/**
 * 使用AR,要求实体类需要继承MP中的Model
 * Model中提供了对数据库的CRUD的操作
 */
public class Dept extends Model<Dept> {
    //定义属性, 属性名和表的列名一样

    @TableId(value = "id",type = IdType.AUTO)
    private String id;
    private String name;
    private String mobile;
    private Integer manager;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public Integer getManager() {
        return manager;
    }

    public void setManager(Integer manager) {
        this.manager = manager;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", mobile='" + mobile + '\'' +
                ", manager=" + manager +
                '}';
    }
}

Mapper接口

不适用Mapper也需要定义这个类,MP通过mapper获取到表的结构

不定义时,MP报错无法获取表的结构信息

package com.wkcto.plus.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wkcto.plus.entity.Dept;

/**
 * DeptMapper是不需要使用的,MP需要使用DeptMapper获取到数据库的表的信息。
 * 如果不定义DeptMapper, MP会报错, 找不到表的定义信息
 */
public interface DeptMapper extends BaseMapper<Dept> {
}

AR-insert

@Test
public void testARInsert(){
    //定义dept的实体
    Dept dept  = new Dept();
    dept.setName("行政部");
    dept.setMobile("010-66666666");
    dept.setManager(5);
    //调用实体对象自己的方法,完成对象自身到数据库的添加操作
    boolean flag = dept.insert();
    System.out.println("ar insert result:"+flag);
}

AR-update

创建实体对象,对要更新的属性赋值,null的属性不更新,根据主键更新记录.

返回值时boolean,true更新成功,没有更新记录时false

@Test
public void testARUpdate(){
    //定义实体Dept
    Dept dept  = new Dept();
   // dept.setId(2);
    dept.setMobile("010-22222222");
    dept.setName("改为市场部");
    dept.setManager(2);
    //根据主键id更新记录
    // UPDATE dept SET name=?, mobile=?, manager=? WHERE id=?  // id = 1
    boolean result = dept.updateById();//使用dept实体主键的值,作为where id = 1
    System.out.println("ar updateById result:"+result);
}

@Test
public void testARUpdate2(){
    //定义实体Dept
    Dept dept  = new Dept();
   // dept.setId(1);
    dept.setMobile("010-3333333");
    //name , manager是没有修改的

    //根据主键id更新记录
    // UPDATE dept SET name=?, mobile=?, manager=? WHERE id=?  // id = 1
    // null的属性值不做更新处理,在update中没有null的字段
    //UPDATE dept SET mobile=? WHERE id=?
    boolean result = dept.updateById();//使用dept实体主键的值,作为where id = 1
    System.out.println("ar updateById result:"+result);
}

AR-delete

使用主键作为删除条件,deleteById()参数是主键值.

返回值始终是true.

删除返回值判断条件是 result>=0,只要sql语法是正确的,返回就是true.和删除记录的数量无关.

/**
 * deleteById()删除操作即使没有从数据库中删除数据,也返回是true
 */
@Test
public void testARDeleteById(){
    Dept dept  = new Dept();
    //DELETE FROM dept WHERE id=?
    boolean result = dept.deleteById(1);
    System.out.println("ar deleteById result:"+result);
}

AR-select

  • 对象调用selectById()

    对象提供主键值,调用selectById()无参数,返回值是查询的结果对象;没有查询到对象,返回null

    不提供主键id值,报错

    /**
      * selectByID
      * 1.按实体的主键能查找出数据,返回对象
      * 2.按实体的主键不能查出数据,是null ,不报错。
      */
    @Test
     public void testARSelectById(){
         Dept dept = new Dept();
         //设置主键的值
       // dept.setId(1);
         //调用查询方法
        //SELECT id,name,mobile,manager FROM dept WHERE id=?
        Dept dept1 = dept.selectById();
        System.out.println("ar selectById result:"+dept1);
    }
    
  • 创建对象,不设置id主键值,selectById()的参数是查询条件,和对象的属性值无关.

    返回值是结果对象,id不存在返回null

    /**
     * selectById(主键)
     * 1.主键有记录,返回实体对象
     * 2.主键没有记录,返回是null
     *
     */
    @Test
    public void testARSelectById2(){
        Dept dept = new Dept();
        Dept dept1 = dept.selectById(3);
        System.out.println("dept1:"+dept1);
    }
    

列和表

主键类型

使用@TableId注解指定主键

/**
 * 指定主键的方式:
 * value:主键字段的名称, 如果是id,可以不用写。
 * type:指定主键的类型, 主键的值如何生成。 idType.AUTO 表示自动增长。
 */
@TableId(
        value="id",
        type = IdType.AUTO
)
  • value=数据库字段名
  • type=主键类型

IdType是枚举类

在这里插入图片描述

  • AUTO:自动增长(mysql,sql server)
  • NONE:没有主键
  • INPUT:手工输入
  • ID_WORKER:实体类用Long id,表的列用bigint,int类型大小不够
  • UUID:实体类使用String id,列使用varchar 50
  • ID_WORKER_STR:实体类使用String id,表的列使用varchar 50

id_worker:Twitter 雪花算法-分布式 ID

指定表名

定义实体类,默认的表名和实体类同名

如果不一致,在实体类定义上面使用@TableName注解

@TableName(
        value = "user_address"
)
public class Address {
    
}

指定列名

实体类属性名默认和表的字段名同名

如果不一致,使用@TableFiled注解

@TableName(
        value = "user_address"
)
public class Address {

    //指定主键
    @TableId(value="user_id",type  = IdType.AUTO)
    private Integer id;
    /**
     * @TableField : 指定属性和列名的对应关系。
     *    属性: value 指定列名
     */
    @TableField(value = "user_city")
    private String city;
    @TableField(value = "user_street")
    private String street;
    private String zipcode;
}

驼峰命名

数据库列名使用下划线,属性名是驼峰命名方式。MyBatis默认支持这种规则

在这里插入图片描述

@TableName(value = "customer")
public class Customer {

    //定义属性
    @TableId(value="id",type = IdType.AUTO)
    private Integer id;
    private String custName;
    private int custAge;
    private String custEmail;
}

自定义sql

创建表

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(80) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `email` varchar(80) DEFAULT NULL,
  `status` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

创建实体

package com.qin.mp.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;

public class Student {
    //定义属性
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    private Integer status;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", status=" + status +
                '}';
    }
}

创建Mapper

package com.qin.mp.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qin.mp.entity.Student;

import java.util.List;

public interface StudentMapper extends BaseMapper<Student> {
    //自定义方法
    public int insertStudent(Student student);
    public Student selectStudentById(Integer id);
    public List<Student> selectByName(String name);
}

创建sql映射xml文件

注意 namespace=“类的全限定名”(可以起别名)

将xml文件放入 resources文件下新建文件夹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.qin.mp.mapper.StudentMapper">
    <insert id="insertStudent">
        insert into student (name,age,email,status) values (#{name},#{age},#{email},#{status})
    </insert>

    <select id="selectStudentById" resultType="com.qin.mp.entity.Student">
        select id,name,age,email,status from student where id=#{id}
    </select>

    <select id="selectByName" resultType="com.qin.mp.entity.Student">
        select id,name,age,email,status from student where name=#{name}
    </select>
</mapper>

配置xml文件位置

application.yml:

mybatis-plus:
  mapper-locations: classpath*:xml/*Mapper.xml

测试

package com.qin.mp;

import com.qin.mp.entity.Student;
import com.qin.mp.mapper.StudentMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class StudentTest {
    @Autowired
    private StudentMapper studentMapper;

    @Test
    public void testInsertStudent(){
        Student student = new Student();
        student.setName("张三");
        student.setAge(17);
        student.setEmail("zhangsan@qq.com");
        student.setStatus(1);
        int rows = studentMapper.insertStudent(student);
        System.out.println("insertStudent rows:"+rows);
    }
}
/*
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3d4e405e] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1938047257 wrapping com.mysql.cj.jdbc.ConnectionImpl@44f24a20] will not be managed by Spring
==>  Preparing: insert into student (name,age,email,status) values (?,?,?,?) 
==> Parameters: 张三(String), 17(Integer), zhangsan@qq.com(String), 1(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3d4e405e]
insertStudent rows:1
*/

查询和分页

查询

Wrapper

QueryWrapper(LambdaQueryWrapper)和UpdateWrapper(LambdaUpdateWrapper)的父类用于生成sql的where条件,entity属性也用于生成sql的where条件.

Mybaits-Plus 3.x 开始支持lambda表达式,LambdaQueryWrapper,LambdaUpdateWrapper支持lambda表达式的构造查询条件

条件

条件说明
allEq基于map的相等
eq等于 =
ne不等于 <>
gt大于 >
ge大于等于 >=
lt小于 <
le小于等于 <=
betweenBETWEEN 值1 AND 值2
notBetweenNOT BETWEEN 值1 AND 值2
likeLIKE ‘%值%’
notLikeNOT LIKE ‘%值%’
likeLeftLIKE ‘%值’
likeRightLIKE ‘值%’
isNull字段 IS NULL
isNotNull字段 IS NOT NULL
in字段 IN(value1,value2,…)
notIn字段 NOT IN(value1,value2,…)
inSql字段 IN (sql语句)
groupByGROUP BY 字段
orderByAscORDER BY 字段, … ASC
orderByDescORDER BY 字段, … DESC
orderBy自定义字段排序
orderBy(true,ture,“id”,“name”)
having条件分组
orOR语句,拼接 + OR 字段 = 值
andAND语句, 拼接 + AND 字段 = 值
apply拼接sql
last在sql语句后拼接自定义条件
exists拼接EXISTS(sql语句)
notExists拼接 NOT EXISTS(语句)
  • QueryWrapper:查询条件封装类

    方法说明
    select设置查询字段select后面的内容
  • UpdateWrapper:更新条件封装类

    方法说明
    set设置要更新的字段,MP拼接sql语句
    setSql参数是sql语句,MP不在处理语句

操作演示

新建数据库

在这里插入图片描述

package com.wkcto.plus;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wkcto.plus.entity.Student;
import com.wkcto.plus.mapper.StudentMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SuppressWarnings("all")
@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentTest {

    //定义StudentMapper
    @Autowired
    private StudentMapper studentDao;
    @Test
    public void testAllEq() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //组装条件
        Map<String, Object> param = new HashMap<>();
        //map<key,value> key列名 , value:查询的值
        param.put("name", "张三");
        param.put("age", 22);
        param.put("status", 1);

        qw.allEq(param);
        //调用MP自己的查询方法
        //SELECT id,name,age,email,status FROM student WHERE name = ? AND age = ?
        //WHERE name = ? AND age = ? AND status = ?
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println(stu));
    }
    /**
     * 1) Map对象中有 key的value是null
     * 使用的是 qw.allEq(param,true);
     * 结果:WHERE name = ? AND age IS NULL
     * <p>
     * 2) Map对象中有 key的value是null
     * qw.allEq(param,false);
     * 结果:WHERE name = ?
     * <p>
     * 结论:
     * allEq(map,boolean)
     * true:处理null值,where 条件加入 字段 is null
     * false:忽略null ,不作为where 条件
     */
    @Test
    public void testAllEq2() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //组装条件
        Map<String, Object> param = new HashMap<>();
        //map<key,value> key列名 , value:查询的值
        param.put("name", "张三");
        //age 是 null
        param.put("age", null);
        //allEq第二个参数为true
        qw.allEq(param, false);
        //调用MP自己的查询方法
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println(stu));
    }
    /**
     * eq使用
     * eq("列名",值)
     */
    @Test
    public void testEq() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //组成条件
        qw.eq("name", "李四");
        //WHERE name = ?
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println("查询eq:" + stu));

    }
    /**
     * ne使用
     * ne表示不等于 <>
     * <p>
     * ne("列名",值)
     */
    @Test
    public void testNe() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //组成条件
        qw.ne("name", "张三");
        // WHERE name <> ?
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println("查询ne:" + stu));
    }
    /**
     * gt 大于( > )
     */
    @Test
    public void testGt() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.gt("age", 30); //age > 30
        // WHERE age > ?
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println("stu:" + stu));
    }
    /**
     * ge 大于等于 ( >=)
     */
    @Test
    public void testGe() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.ge("age", 31);// >=31
        //WHERE age >= ?
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println("student:" + stu));
    }
    /**
     * lt 小于 ( < )
     */
    @Test
    public void testLt() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.lt("age", 32);
        // WHERE age < ?
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println("student:" + stu));
    }
    /**
     * le 小于 ( <= )
     */
    @Test
    public void testLe() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.le("age", 32);
        //  WHERE age <= ?
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println("student:" + stu));
    }
    /**
     * between ( ? and ? )
     */
    @Test
    public void testBetween() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //between("列名",开始值,结束值)
        qw.between("age", 22, 28);
        // where age >= 22 and age <= 28
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println(stu));
    }
    /**
     * notBetween(不在范围区间内)
     */
    @Test
    public void testNotBetween() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.notBetween("age", 18, 28);
        //WHERE age NOT BETWEEN ? AND ?
        // where age < 18 or age > 28
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println(stu));
    }
    /**
     * like 匹配某个值
     */
    @Test
    public void testLike() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.like("name", "张");
        // WHERE name LIKE %张%
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println(stu));
    }
    /**
     * notLike 不匹配某个值
     */
    @Test
    public void testNotLike() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.notLike("name", "张");
        //  WHERE name NOT LIKE ?  %张%
        List<Student> students = studentDao.selectList(qw);
        students.forEach(stu -> System.out.println(stu));
    }
    /**
     * likeLeft "%值"
     */
    @Test
    public void testLikeLeft() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.likeLeft("name", "张");
        //WHERE name LIKE %张
        List<Student> students = studentDao.selectList(qw);
        students.forEach(student -> System.out.println(student));
    }
    /**
     * likeRight "%值"
     */
    @Test
    public void testLikeRight() {
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.likeRight("name", "李");
        //WHERE name LIKE 李%
        List<Student> students = studentDao.selectList(qw);
        students.forEach(student -> System.out.println(student));
    }
    /**
     * isNull , 判断字段是 null
     */
    @Test
    public void testIsNull(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //判断email is null
        //WHERE email IS NULL
        qw.isNull("email");
        print(qw);
    }
    /**
     * isNotNull , 判断字段是 is not null
     */
    @Test
    public void testIsNotNull(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        // WHERE email IS NOT NULL
        qw.isNotNull("email");
        print(qw);
    }
    /**
     * in 值列表
     */
    @Test
    public void testIn(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //in(列名,多个值的列表)
        //WHERE name IN (?,?,?)
        qw.in("name","张三","李四","周丽");
        print(qw);

    }
    /**
     * notIn 不在值列表
     */
    @Test
    public void testNoIn(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //in(列名,多个值的列表)
        //WHERE name NOT IN (?,?,?)
        qw.notIn("name","张三","李四","周丽");
        print(qw);
    }
    /**
     * in 值列表
     */
    @Test
    public void testIn2(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        List<Object> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        //WHERE status IN (?,?)
        qw.in("status",list);
        print(qw);
    }
    /**
     * inSql() : 使用子查询
     */
    @Test
    public void testInSQL(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //WHERE age IN (select age from student where id=1)
        qw.inSql("age","select age from student where id=1");
        print(qw);
    }
    /**
     * notInSql() : 使用子查询
     */
    @Test
    public void testNotInSQL(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //WHERE age NOT IN (select age from student where id=1)
        qw.notInSql("age","select age from student where id=1");
        print(qw);
    }
    private void print(QueryWrapper qw){
        List<Student> students = studentDao.selectList(qw);
        students.forEach(student -> System.out.println(student));
    }
    /**
     * groupBy:分组
     */
    @Test
    public void testGroupby(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.select("name,count(*) personNumbers");//select name,count(*) personNumbers
        qw.groupBy("name");
        // SELECT name,count(*) personNumbers FROM student GROUP BY name
        print(qw);
    }
    /**
     * orderbyAsc : 按字段升序
     */
    @Test
    public void testOrderByAsc(){
        QueryWrapper<Student> qw= new QueryWrapper<>();
        //FROM student ORDER BY name ASC , age ASC
        qw.orderByAsc("name","age");
        print(qw);
    }
    /**
     * orderbyDesc : 按字段降序
     */
    @Test
    public void testOrderByDesc(){
        QueryWrapper<Student> qw= new QueryWrapper<>();
        // ORDER BY name DESC , id DESC
        qw.orderByDesc("name","id");
        print(qw);
    }
    /**
     * order :指定字段和排序方向
     *
     * boolean condition : 条件内容是否加入到 sql语句的后面。
     * true:条件加入到sql语句
     * FROM student ORDER BY name ASC
     *
     * false:条件不加入到sql语句
     * FROM student
     */
    @Test
    public void testOrder(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        qw.orderBy(true,true,"name")
                .orderBy(true,false,"age")
                .orderBy(true,false,"email");
        // name asc, age desc , email desc
        //FROM student ORDER BY name ASC , age DESC , email DESC
        print(qw);
    }
    /**
     * and ,or方法
     */
    @Test
    public void testOr(){
        QueryWrapper<Student> qw= new QueryWrapper<>();
        //WHERE name = ? OR age = ?
        qw.eq("name","张三")
                .or()
                .eq("age",22);
        print(qw);
    }
    /**
     * last : 拼接sql语句到MP的sql语句的最后
     */
    @Test
    public void testLast(){
        QueryWrapper<Student> qw = new QueryWrapper<>();
        //SELECT id,name,age,email,status FROM student WHERE name = ? OR age = ? limit 1
        qw.eq("name","张三")
                .or()
                .eq("age",22)
                .last("limit 1");
        print(qw);

    }
    /**
     * exists : 判断条件
     *
     * notExists
     */
    @Test
    public void testExists(){
        QueryWrapper<Student> qw= new QueryWrapper<>();
        //SELECT id,name,age,email,status FROM student
        // WHERE EXISTS (select id from student where age > 20)
        //qw.exists("select id from student where age > 90");

        //SELECT id,name,age,email,status FROM student WHERE
        // NOT EXISTS (select id from student where age > 90)

        qw.notExists("select id from student where age > 90");
        print(qw);
    }
}

分页

前提:配置分页插件,实现物理分页.默认是内存分页.

package com.wkcto.plus.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {

    /***
     * 定义方法,返回的返回值是java 对象,这个对象是放入到spring容器中
     * 使用@Bean修饰方法
     * @Bean等同于<bean></bean>
     */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }
}

分页查询

/**
 * 分页:
 * 1.统计记录数,使用count(1)
 *    SELECT COUNT(1) FROM student WHERE age > ?
 * 2.实现分页,在sql语句的末尾加入 limit 0,3
 *    SELECT id,name,age,email,status FROM student WHERE age > ? LIMIT 0,3
 */
@Test
public void testPage(){
    QueryWrapper<Student> qw = new QueryWrapper<>();
    qw.gt("age",22);
    IPage<Student> page  = new Page<>();
    //设置分页的数据
    page.setCurrent(1);//第一页
    page.setSize(3);// 每页的记录数

    IPage<Student> result = studentDao.selectPage(page,qw);

    //获取分页后的记录
    List<Student> students = result.getRecords();
    System.out.println("students.size()="+students.size());
    //分页的信息
    long pages  = result.getPages();
    System.out.println("页数:"+pages);
    System.out.println("总记录数:"+result.getTotal());
    System.out.println("当前页码:"+result.getCurrent());
    System.out.println("每页的记录数:"+result.getSize());
}
lect id from student where age > 90)

        qw.notExists("select id from student where age > 90");
        print(qw);
    }
}

分页

前提:配置分页插件,实现物理分页.默认是内存分页.

package com.wkcto.plus.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {

    /***
     * 定义方法,返回的返回值是java 对象,这个对象是放入到spring容器中
     * 使用@Bean修饰方法
     * @Bean等同于<bean></bean>
     */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }
}

分页查询

/**
 * 分页:
 * 1.统计记录数,使用count(1)
 *    SELECT COUNT(1) FROM student WHERE age > ?
 * 2.实现分页,在sql语句的末尾加入 limit 0,3
 *    SELECT id,name,age,email,status FROM student WHERE age > ? LIMIT 0,3
 */
@Test
public void testPage(){
    QueryWrapper<Student> qw = new QueryWrapper<>();
    qw.gt("age",22);
    IPage<Student> page  = new Page<>();
    //设置分页的数据
    page.setCurrent(1);//第一页
    page.setSize(3);// 每页的记录数

    IPage<Student> result = studentDao.selectPage(page,qw);

    //获取分页后的记录
    List<Student> students = result.getRecords();
    System.out.println("students.size()="+students.size());
    //分页的信息
    long pages  = result.getPages();
    System.out.println("页数:"+pages);
    System.out.println("总记录数:"+result.getTotal());
    System.out.println("当前页码:"+result.getCurrent());
    System.out.println("每页的记录数:"+result.getSize());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值