mybatis-plus实战学习

mybatis-plus学习笔记

  • java中访问数据库各种方式的区别
  • mybatis-plus入门
    • 开发步骤
      • 新建springboot工程
      • 添加maven依赖
      • 数据库配置
      • 实体类
      • 创建Dao接口
      • 在springboot的启动类上,加入Maper扫描器
      • 测试使用
  • 配置mybatis日志
  • CRUD基本用法
  • ActiveRecord(AR)
    • AR之insert
  • 表和列
    • 指定表名
    • 驼峰命名
  • 自定义sql
  • 查询和分页
    • 查询构造器:Wrapper
    • QueryWrapper:查询条件封装类
    • UpdateWrapper:更新条件封装类
  • 查询
    • allEq
    • eq
    • ne
    • gt
    • ge
    • lt
    • le
    • between
    • notBetween
    • like,notlike
    • likeLeft,liekRight
    • isNull,isNotNull
    • in,notIn
    • inSql,notInSql
    • groupBy
    • orderByAsc,orderByDesc,orderBy
    • or,and
    • last
    • exists,notExists
  • 分页
  • 通用service
    • crud
    • 分页查询
  • 条件构造器
  • id生成策略
  • 逻辑删除
  • 数据自动填充
  • 执行 SQL 分析打印
  • 数据安全保护
  • 乐观锁
  • 代码生成器
    • 快速入门
    • 代码生成器(3.5.1+版本)快速入门
    • 官网代码生成器(3.5.1+)
      • 数据库配置
      • 包配置

java中访问数据库各种方式的区别

mybatis-plus实战学习_第1张图片

mybatis-plus入门

开发步骤

新建springboot工程

添加maven依赖

pom依赖


<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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.5.6version>
        <relativePath/> 
    parent>
    <groupId>com.examplegroupId>
    <artifactId>demoartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>demoname>
    <description>Demo project for Spring Bootdescription>
    <properties>
        <java.version>1.8java.version>
    properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.4.3.4version>
        dependency>
        
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.27version>
        dependency>
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.22version>
        dependency>
    dependencies>
project>

数据库配置

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
server:
  port: 9090

实体类

package com.example.demo.entity;

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

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

创建Dao接口

Mapper

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;

/**
 * 自定义Maper,就是Dao接口
 * 1、要实现BaseMapper
 * 2、指定实体类
 * BaseMapper是MP框架中的对象,定义17个操作方法(CRUD)
 */
public interface UserMapper extends BaseMapper<User> {
}

在springboot的启动类上,加入Maper扫描器

package com.example.demo;

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

/**
 * @MapperScan 注解,扫描器,指定Mapper类所在的包
 */
@SpringBootApplication
@MapperScan(value = "com.example.demo.mapper")
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

测试使用

在测试类或service注入Dao接口,框架实现动态代理创建Dao的实体类对象,
调用BaseMapper中的方法,完成CRUD
测试

package com.example.demo;

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

import javax.annotation.Resource;
import java.util.List;

@SpringBootTest
class DemoApplicationTests {
    //使用自动注入,注入Mapper对象(Dao)
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testUser(){
        User user =new User();
        user.setName("张三");
        user.setAge(2);
        user.setEmail("[email protected]");
        //调用userMapper的方法,也就是父接口BaseMapper中提供的方法
        int rows = userMapper.insert(user);
        System.out.println("insert的结果:"+rows);
    }

}

输出insert的结果:1

配置mybatis日志

控制台输出正在执行的sql语句
application.yml

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

CRUD基本用法

  • insert
public void testUser(){
        User user =new User();
        user.setName("zhangsan");
        user.setAge(2);
        user.setEmail("[email protected]");
        //调用userMapper的方法,也就是父接口BaseMapper中提供的方法
        int rows = userMapper.insert(user);
        System.out.println("insert的结果:"+rows);
    }
//添加数据后,获取主键值
    @Test
    public void testInsertGetId(){
        User user =new User();
        user.setName("李斯");
        user.setAge(2);
        user.setEmail("[email protected]");
        int rows=userMapper.insert(user);
        System.out.println("insert的结果:"+rows);
        //获取刚添加到数据库中的数据的主键id
        System.out.println("主键id="+user.getId());
    }

mybatis-plus实战学习_第2张图片

  • update
 /**
     * 更新操作update
     */
    @Test
    public void testUpdate(){
        User user =new User();
        user.setName("修改的数据");
        user.setEmail("[email protected]");
        user.setId(6L);;
        /**
         * 执行更新,根据主键值更新
         * UPDATE user SET name=?, email=? WHERE id=?
         * 更新了所有非null属性值,根据WHERE id=主键值
         */
        int rows=userMapper.updateById(user);
        System.out.println("update rows: " +rows);
    }

在这里插入图片描述

/**
     * 控制更新的属性
     */
    @Test
    public void testUpdate2(){
        User user =new User();
        user.setId(2L);;
        user.setName("张三");
        /**
         * 更新属性
         * UPDATE user SET name=? WHERE id=?
         */
        int i = userMapper.updateById(user);
        System.out.println("i="+i);
    }

在这里插入图片描述

 /**
     * 更新数据,实体类的属性是基本类型-int age
     * 实体类属性:推荐使用包装类型,可以判断是否为null
     * 基本数据类型都有默认值,在不赋值的情况下,会在数据库中插入默认的值,
     */
    @Test
    public void testUpdate3(){
        User user =new User();
        user.setId(3L);
        user.setEmail("[email protected]");
        /**
         * 实体对象user:{name=null,email=”[email protected]“,age=0,
         * 没有修改name,age
         * 判断字段是否要修改,加入到set语句,是根据属性值是否为null
         *  UPDATE user SET age=?, email=? WHERE id=?
         */
        int rows = userMapper.updateById(user);
        System.out.println("rows="+rows);
    }

在这里插入图片描述

  • delete
 /**
     * 根据id删除
     * 按主键删除一条数据
     * 方法是deleteById()
     * 参数:主键值
     * 返回值:是删除的成功记录数
     */
    @Test
    public void testDelete(){
        //DELETE FROM user WHERE id=?
        int rows =userMapper.deleteById(3);
        System.out.println("rows="+rows);
    }

在这里插入图片描述
主键不存在的时候,删除0行
在这里插入图片描述

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

在这里插入图片描述

  /**
     * 批处理方式:使用多个主键值,删除数据
     * 方法民初:deleteBatchIds()
     * 参数:Collection idList
     * 返回值是删除的记录数
     */
    @Test
    public void testDeleteBatchIds(){
        List<Integer>ids=new ArrayList<>();
        ids.add(1);
        ids.add(5);
        ids.add(6);
        //DELETE FROM user WHERE id IN ( ? , ? , ? )
        int rows=userMapper.deleteBatchIds(ids);
        System.out.println("rows="+rows);
    }

在这里插入图片描述
使用lamda表达式创建list集合

/**
     * 批处理方式:使用多个主键值,删除数据
     * 方法民初:deleteBatchIds()
     * 参数:Collection idList
     * 返回值是删除的记录数
     */
    @Test
    public void testDeleteBatchIds(){
        //使用lamda表达式创建list集合
        List<Integer>ids= Stream.of(2,4).collect(Collectors.toList());
        //DELETE FROM user WHERE id IN ( ? , ? , ? )
        int rows=userMapper.deleteBatchIds(ids);
        System.out.println("rows="+rows);
    }
  • select
 /**
     *实现查询selectById,根据主键值查询
     * 参数:主键值
     *  返回值:实体对象(唯一的一个对象)
     */
    @Test
    public void testSelectById(){
        User user =userMapper.selectById(1);
        /**
         * SELECT id,name,age,email FROM user WHERE id=?
         * 如果根据主键没有查找到数据,得到的返回值是null
         */
        // 在使用对象之前,需要判断对象是否为null
        if(user!=null){
            //业务方法的调用
        }
        System.out.println("user="+user);
    }

在这里插入图片描述

  /**
     * 实现批处理查询,根据多个主键值查询,获取到list
     * 方法:selectBatchIds
     * 参数:id的集合
     * 返回值List
     */
    @Test
    public void testSelectBatchIds(){
        //lambda表达式
        //SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
        List<Integer>ids=Stream.of(4,8,9).collect(Collectors.toList());
        List<User>users=userMapper.selectBatchIds(ids);
        for (User user:users){
            System.out.println(user);
        }
    }

mybatis-plus实战学习_第3张图片

/**
     * 使用Map做条件查询
     * 方法:selectMap()
     * 参数:Mapkey为参数名,value为条件
     * 返回值:List
     */
    @Test
    public void testSelectMap(){
        //创建Map,封装查询条件
        Map<String,Object>map=new HashMap<>();
        //key是字段名,value:字段值,多个key,and连接
        map.put("name","zhangsan");
        map.put("age",20);
        List<User>users=userMapper.selectByMap(map);
        //SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
        users.forEach(user -> {
            System.out.println(user);
        });
    }

mybatis-plus实战学习_第4张图片
mybatis-plus的CRUD底层源码调用的是mybatis的SqlSession的方法

ActiveRecord(AR)

ActiveRecord

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

AR之insert

1、dept表设计
mybatis-plus实战学习_第5张图片
2、entity实体类

package com.example.demo.entity;

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

/**
 * 必须继承Model,Model定义了表的CRUD方法,Dept属性名和列名是一样的
 */
@Data
public class Dept extends Model<Dept> {
    @TableId(value = "id",type = IdType.AUTO)//自动增长,数据库中的字段为id
    private Integer id;
    private String name;
    private String mobile;
    private Integer manager;
}

3、Mapper

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.Dept;

/**
 * 不使用DeptMapper,也需要定义这个类,MP通过mapper获取表的结构
 * 不定义DeptMapper,MP会报错,找不到表的定义信息
 */
public interface DeptMapper extends BaseMapper<Dept> {
}

4、测试AR

package com.example.demo;

import com.example.demo.entity.Dept;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class DeptARTest {
    @Test
    public void testARInsert(){
        Dept dept = new Dept();
        dept.setName("销售部");
        dept.setMobile("010-12345678");
        dept.setManager(1);
        //调用实体对象自己的方法,完成对象自身到数据库的操作
        boolean flag = dept.insert();
        System.out.println("insert="+flag);
    }
}

在这里插入图片描述

@Test
    public void testUpdateById(){
        Dept dept =new Dept();
        dept.setId(3);
        dept.setManager(2);
        /**
         * 根据主键id更新数据
         * UPDATE dept SET manager=? WHERE id=?
         * 主键不能为空,否则更新失败
         * 主键在数据库中不存在,更新返回false
         * null的属性值不做更新处理,在update中没有null的字段
         */
        boolean flag =dept.updateById();
        System.out.println("update flag="+flag);
    }

在这里插入图片描述

 @Test
    public void testARDelete(){
        Dept dept =new Dept();
        dept.setId(1);
        /**
         * DELETE FROM dept WHERE id=?
         * deleteById()删除操作即使没有从数据库中删除数据,也返回是true
         * deleteById(1)传参,没有删除成功返回的是false
         */
        boolean flag = dept.deleteById();//拿实体自身的id作为删除的主键
        boolean result=dept.deleteById(1);
        System.out.println("删除是否成功:"+flag);
        System.out.println("result="+result);
    }
  @Test
    public void testSelectById(){
        Dept dept =new Dept();
        dept.setId(1);
        /**
         * SELECT id,name,mobile,manager FROM dept WHERE id=?
         * selectById
         * 1.按实体的主键能查出数据,返回对象
         * 2.按实体的主键不能查出数据,返回null,不报错
         */
        Model model=dept.selectById();
        System.out.println(model);
    }

    /**
     * selectById(主键)
     * 1.主键有记录,返回实体对象
     * 2.主键没有记录,返回是null,不报错
     * 3.主键参数为null,返回是null
     */
    @Test
    public void testSelect(){
        Dept dept =new Dept();
        Dept dept2=dept.selectById(null);
        System.out.println(dept2);
    }

表和列

主键,TableName,TableId
IdType枚举类,主键定义如下:
mybatis-plus实战学习_第6张图片

指定表名

mybatis-plus实战学习_第7张图片

mybatis-plus实战学习_第8张图片
实体类

package com.example.demo.entity;

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

/**
 * @TableName(value = "表名")
 */
@Data
@TableName(value = "address")
public class Address {
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    /**
     *  @TableField:指定属性和列名的对应关系
     *  属性:value指定列名(数据库里对应的列名)
     */
    @TableField(value = "city")
    private String city;
    private String street;
    private String zipcode;
}


Mapper

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.Address;

public interface AddressMapper extends BaseMapper<Address> {
}

测试

package com.example.demo;

import com.example.demo.entity.Address;
import com.example.demo.mapper.AddressMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class AddressTest {
    @Resource
    public AddressMapper addressMapper;
    @Test
    public void testInsert(){
        Address address = new Address();
        address.setCity("北京");
        address.setStreet("长安大街");
        address.setZipcode("010");
        int rows=addressMapper.insert(address);
        System.out.println("rows="+rows);
    }
}

在这里插入图片描述

驼峰命名

在这里插入图片描述

在这里插入图片描述
实体类

package com.example.demo.entity;

import lombok.Data;

@Data
public class Customer {
    private Integer id;
    private String custName;
    private String custEmail;
    private Integer custAge;
}

Mapper

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.Customer;

public interface CustomerMapper extends BaseMapper<Customer> {
}

测试

package com.example.demo;

import com.example.demo.entity.Customer;
import com.example.demo.mapper.CustomerMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class CustomerTest {
    @Resource
    public CustomerMapper dao;
    @Test
    public void test(){
        Customer customer =new Customer();
        customer.setCustName("张三");
        customer.setCustAge(28);
        customer.setCustEmail("[email protected]");
        int rows=dao.insert(customer);
        System.out.println("rows="+rows);
        /**
         * INSERT INTO customer ( cust_name, cust_email, cust_age ) VALUES ( ?, ?, ? )
         * Parameters: 张三(String), [email protected](String), 28(Integer)
         * rows=1
         */
    }
}

自定义sql


mybatis-plus实战学习_第9张图片
实体类

package com.example.demo.entity;

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

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

}

Mapper

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.Student;

import java.util.List;

public interface StudentMapper extends BaseMapper<Student> {
    List<Student > selectByName();
    public int insertStudent(Student student);
    public Student selectStudentByName(String name);
}

新建sq映射文件


DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.StudentMapper">
    <select id="selectByName" resultType="com.example.demo.entity.Student">
        select id,name,age,email,status from student order by id limit 10
    select>
    <insert id="insertStudent" parameterType="com.example.demo.entity.Student">
        insert into student (name,age,email,status) values(#{name},#{age},#{email},#{status})
    insert>
    <select id="selectStudentByName" resultType="com.example.demo.entity.Student">
        select id,name,age,email,status from student where name =#{name}
    select>
mapper>

配置xml文件位置
mybatis-plus实战学习_第10张图片
测试

package com.example.demo;

import com.example.demo.entity.Student;
import com.example.demo.mapper.StudentMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class StudentTest {
    @Resource
    private StudentMapper mapper;
    @Test
    public void testInsert(){
        /**
         * insert into student (name,age,email,status) values(?,?,?,?)
         */
        Student student = new Student();
        student.setName("李四");
        student.setEmail("[email protected]");
        student.setAge(20);
        student.setStatus(1);
        mapper.insertStudent(student);
    }
    @Test
    public void testSeectById(){
        /**
         * select id,name,age,email,status from student where name =?
         */
        Student student = mapper.selectStudentByName("李四");
        /**
         * SELECT id,name,age,email,status FROM student WHERE id=?
         */
        Student  stu = mapper.selectById(2);
        System.out.println(stu);
        if(stu!=null){
            //其他业务操作
        }
        System.out.println(student);
    }
}

查询和分页

查询构造器:Wrapper

mybatis-plus实战学习_第11张图片mybatis-plus实战学习_第12张图片

在idea中ctr+N搜索Wrapper,鼠标选中Wrapper,ctrl+f12查看当前类的结构信息

条件 说明
allEq 基于map的相等
eq 等于=
ne 不等于<>
gt 大于>
ge 大于等于
lt 小于
le 小于等于
betwen betwen 值1 and 值2
notBetween not betwen 值1 and 值2
like Like ‘%值%’
notLike not like ‘%值%’
likeLeft like’%值’
likeRight like ‘值%’
isNull 字段 is null
isNotNull 字段 is not null
in 字段 in (value1,value2,…)
notIn 字段 not in (value1,value2,…)
inSql 字段 in (sql语句)
notInSql 字段 NOT IN ( sql语句 )
groupBy GROUP BY 字段
orderByAsc ORDER BY 字段, … ASC
orderByDesc ORDER BY 字段, … DESC
orderBy ORDER BY 字段, …例: orderBy(true, true, “id”, “name”)—>order by id ASC,name ASC
having HAVING ( sql语句 ) 条件分组
or or 语句,拼接 +OR 字段=值
and And语句,拼接+AND 字段=值
apply 拼接sql
last 在sql语句后拼接自定义条件
exists 拼接exists(sql语句)exists(“select id from table where age = 1”)—>exists (select id from table where age = 1)
notExists 拼接 NOT EXISTS ( sql语句 )
nested 正常嵌套不带and或者or

QueryWrapper:查询条件封装类

方法 说明
select 设置 查询字段select后面的内容

UpdateWrapper:更新条件封装类

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

查询

Student表:初始数据
mybatis-plus实战学习_第13张图片

allEq

以Map为参数条件
1、条件:name是张三,age=22

 @Test
    public void testAllEq(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        Map<String,Object>map=new HashMap<>();
        map.put("name","张三");
        map.put("age",22);
        //组装条件
        queryWrapper.allEq(map);
        /**
         * Map,key:对应列名,value:查询的值
         * SELECT id,name,age,email,status FROM student WHERE (name = ? AND age = ?)
         * Parameters: 张三(String), 22(Integer)
         *输出
         * Student(id=3, name=张三, age=22, [email protected], status=1)
         */
        List<Student>students=mapper.selectList(queryWrapper);//调用mp自己的查询方法
        students.forEach(student -> {
            //循环遍历输出
            System.out.println(student);
        });
    }
 @Test
    public void testAllEq2(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        Map<String,Object>map=new HashMap<>();
        map.put("name","张三");
        map.put("age",null);
        //组装条件
        /**
         * Map对象中有key的value是null
         * 使用的是queryWrapper.allEq(map,true)
         * 结果:
         * SELECT id,name,age,email,status FROM student WHERE (name = ? AND age IS NULL)
         * 如果使用的是使用的是queryWrapper.allEq(map,false)
         * 结果:
         *  SELECT id,name,age,email,status FROM student WHERE (name = ?)
         *  结论:
         *  allEq(map,boolean)
         *  true:处理null值,where条件加入字段 is null
         *  false:忽略null,不作为where条件
         */
        queryWrapper.allEq(map,false);
        List<Student>students=mapper.selectList(queryWrapper);//调用mp自己的查询方法
        students.forEach(stu-> System.out.println(stu));
    }

eq

等于 =
name等于李四

@Test
    public void testEq(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        /**
         * eq使用
         * eq("列名",值)
         * SELECT id,name,age,email,status FROM student WHERE (name = ?)
         */
        //组成条件
        queryWrapper.eq("name","张三");
        List<Student>students=mapper.selectList(queryWrapper);//调用mp自己的查询方法
        students.forEach(stu-> System.out.println(stu));
    }

ne

ne 不等于

  @Test
    public void testNe(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        /**
         * ne(列名,值)
         * ne不等于
         * SELECT id,name,age,email,status FROM student WHERE (name <> ?)
         */
        queryWrapper.ne("name","张三");
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

gt

gt大于

@Test
    public void testGt(){
        /**
         *SELECT id,name,age,email,status FROM student WHERE (age > ?)
         */
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age",20);
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

ge

ge大于等于

 @Test
    public void testGe(){
        /**
         *SELECT id,name,age,email,status FROM student WHERE (age >= ?)
         */
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.ge("age",30);
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

lt

lt小于

 @Test
    public void testLt(){
        /**
         *SELECT id,name,age,email,status FROM student WHERE (age < ?)
         */
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.lt("age",30);
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

le

le小于等于

@Test
    public void testLe(){
        /**
         *SELECT id,name,age,email,status FROM student WHERE (age <= ?)
         */
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.le("age",30);
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

between

between 在两个值范围之间(包括开始区间和结束区间)

 @Test
    public void testBetween(){
        /**
         *SELECT id,name,age,email,status FROM student WHERE (age BETWEEN ? AND ?)
         * 等于SELECT id,name,age,email,status FROM student WHERE age>=18 and age<=28
         * between("列名",开始值,结束值)
         */
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.between("age",18,28);
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

notBetween

不在范围区间内

@Test
    public void testNotBetween(){
        /**
         * SELECT id,name,age,email,status FROM student WHERE (age NOT BETWEEN ? AND ?)
         * 等于
         * SELECT id,name,age,email,status FROM student WHERE age<18 or age>28
         */
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.notBetween("age",18,28);
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

like,notlike

like 匹配值 “%值”
notLike 不匹配"%值"

 @Test
    public void testLike(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name","张");
        /**
         * ==>  Preparing: SELECT id,name,age,email,status FROM student WHERE (name LIKE ?)
         * ==> Parameters: %张%(String)
         * <==    Columns: id, name, age, email, status
         * <==        Row: 3, 张三, 22, [email protected], 1
         * <==      Total: 1
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }
@Test
    public void testNotLike(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.notLike("name","张");
        /**
         Preparing: SELECT id,name,age,email,status FROM student WHERE (name NOT LIKE ?)
         Parameters: %张%(String)
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

likeLeft,liekRight

likeLeft:LIKE ‘%值’
likeRight:LIKE ‘值%’

 @Test
    public void testLikeLeft(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.likeLeft("name","张");
        /**
         SELECT id,name,age,email,status FROM student where name  like '%张'
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }
    @Test
    public void testLikeRight(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("name","张");
        /**
         SELECT id,name,age,email,status FROM student where name  like '张%'
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

isNull,isNotNull

isNull:字段 IS NULL
isNotNull:字段 IS NOT NULL

@Test
    public void testIsNull(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        /**
         SELECT id,name,age,email,status FROM student WHERE (email IS NULL)
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }
    @Test
    public void testIsNotNull(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.isNotNull("email");
        /**
         SELECT id,name,age,email,status FROM student WHERE (email IS NOT NULL)
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

in,notIn

in后面值列表,在列表中都是符合条件的
notIn 不在列表中的

    @Test
    public void testIn(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.in("name","张三","李四");
        /**
         Preparing: SELECT id,name,age,email,status FROM student WHERE (name IN (?,?))
        Parameters: 张三(String), 李四(String)
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }
    @Test
    public void testNotIn(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.notIn("name","张三","李四");
        /**
         Preparing: SELECT id,name,age,email,status FROM student WHERE (name NOT IN (?,?))
         Parameters: 张三(String), 李四(String)
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

inSql,notInSql

inSql常用来做子查询类似 in()
notInSql 类似notIn()

 @Test
    public void testInSql(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("age","select age from student where id = 1");
        /**
         SELECT id,name,age,email,status FROM student WHERE (age IN (select age from student where id = 1))
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }
    @Test
    public void testNotInSql(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.notInSql("age","select age from student where id = 1");
        /**
         SELECT id,name,age,email,status FROM student WHERE (age not IN (select age from student where id = 1))
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

groupBy

groupBy基于多个字段分组

 @Test
    public void testGroupBy(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.select("name,count(*) personNumbers");
        queryWrapper.groupBy("name");
        /**
         * groupBy 分组
         *  SELECT name,count(*) personNumbers FROM student GROUP BY name
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

orderByAsc,orderByDesc,orderBy

orderByAsc 按字段降序
orderBy 每个字段指定排序方向

   @Test
    public void testOrderBy(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        //orderBy(条件内容是否添加到sql语句后面,true为添加,false为不添加)
        queryWrapper.orderBy(true,true,"name");
        /**
         * orderBy 指定字段和排序方向
         *SELECT id,name,age,email,status FROM student ORDER BY name ASC
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }
    @Test
    public void testOrderBy2(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        //添加多个排序字段
        queryWrapper.orderBy(true,true,"name")
        .orderBy(true,true,"email");
        /**
         * orderBy 指定字段和排序方向
         *SELECT id,name,age,email,status FROM student ORDER BY name ASC,email ASC
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

or,and

or 连接条件用or
and 连接条件用and

@Test
    public void testOr(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name","张三")
                .or()
                .eq("age",20);
        /*
        SELECT id,name,age,email,status FROM student WHERE (name = ? OR age = ?)
         Parameters: 张三(String), 20(Integer)
         */
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

last

last拼接sql语句

@Test
    public void testLst(){
       QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
       /*
       在sql语句最后面拼接sql语句
       Preparing: SELECT id,name,age,email,status FROM student WHERE (name = ? OR age = ?) limit 1
       Parameters: 张三(String), 20(Integer)
        */
       queryWrapper.eq("name","张三")
               .or()
               .eq("age",20)
               .last("limit 1");
       List<Student>students=mapper.selectList(queryWrapper);
       students.forEach(student -> System.out.println(student));
   }

exists,notExists

exists 拼接 EXISTS ( sql语句 )
notExists:是相反的操作

  @Test
    public void testExist(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
       /*
       SELECT id,name,age,email,status FROM student WHERE (EXISTS (select id from student where age>20))
        */
        queryWrapper.exists("select id from student where age>20");
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }
    @Test
    public void testNotExist(){
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
       /*
       SELECT id,name,age,email,status FROM student WHERE (NOT EXISTS (select id from student where age>20))
        */
        queryWrapper.notExists("select id from student where age>20");
        List<Student>students=mapper.selectList(queryWrapper);
        students.forEach(student -> System.out.println(student));
    }

分页

前提:配置分页插件,实现物理分页。默认是内存分页
由于springBoot启动类本身也是一个配置类(@Configuration修饰的类)
可以在springBoot启动类里main方法下面配置分页

package com.example.demo;

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

/**
 * @MapperScan 注解,扫描器,指定Mapper类所在的包
 */
@SpringBootApplication
@MapperScan(value = "com.example.demo.mapper")
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

mybatis-plus 3.4.3.4配置分页插件如下

package com.example.demo.config;

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

/**
 * @Configuration标注的类相当于xml配置文件
 */
@Configuration
public class Config {
    /**
     * 定义方法,方法的返回值是java对象,这个对象是放入到spring容器中
     *  @Bean 等同于
     */
    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //DbType.MYSQL:分页使用的语句是mysql类型
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

测试

    @Test
    public void testPage(){
        /**
         * 分页:
         * 1.统计记录数,使用count(1)
         * select count(1) from student
         * 2.实现分页,在sql语句的末尾加入limit 0,3
         * SELECT id,name,age,email,status FROM student LIMIT 3
         * 要点!! 分页返回的对象与传入的对象是同一个
         *@Param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位(你可以继承Page实现自己的分页对象)
         */
        QueryWrapper<Student>queryWrapper = new QueryWrapper<>();
        IPage<Student>page =new Page<>();
        //设置分页的数据
        page.setCurrent(1);//设置当前页为第一页
        page.setSize(3);//每页的记录数为3
        IPage<Student> result = mapper.selectPage(page,queryWrapper);
        //获取分页后的记录
        List<Student>students = result.getRecords();
        students.forEach(student -> {
            System.out.println(student);
        });
        //分页的信息
        System.out.println("size="+result.getSize());
        System.out.println(result.getPages());
        System.out.println("页数:"+result.getPages());
        System.out.println("总记录数:"+result.getTotal());
        System.out.println("当前的页码:"+result.getCurrent());
        System.out.println("每页的记录数:"+result.getSize());
        /**
         * 输出如下结果
         * size=3
         * 3
         * 页数:3
         * 总记录数:7
         * 当前的页码:1
         * 每页的记录数:3
         */
    }

mybati-plus官网分页的介绍

通用service

crud

package com.example.demo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.entity.Student;

/**
 * mybatis-plus封装的service层的crud接口:IService
 */
public interface StudentService extends IService<Student> {
}

package com.example.demo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.Student;
import com.example.demo.mapper.StudentMapper;
import com.example.demo.service.StudentService;
import org.springframework.stereotype.Service;

/**
 * service实现类
 * 继承mp提供通用的service基类
 * ServiceImpl
 *     2个泛型 1.StudentMapper Mapper接口
 *     2.Student 对应的实体类对象
 */
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper,Student> implements StudentService{
}

测试

package com.example.demo;

import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@SpringBootTest
public class serviceTest {
    @Resource
    private StudentService studentService;
    @Test
    public void getList(){
        /*
            SELECT id,name,age,email,status FROM student
         */
        List<Student> list=studentService.list();
        list.forEach(student -> System.out.println(student));
    }
    @Test
    public void query(){
        /*
            SELECT id,name,age,email,status FROM student WHERE id=?
         */
        Student student = studentService.getById(1);
        System.out.println(student);
    }
    @Test
    public void insetBath(){
        /*
        ==>  Preparing: INSERT INTO student ( name, age, email, status ) VALUES ( ?, ?, ?, ? )
==> Parameters: 测试1(String), 23(Integer), [email protected](String), 1(Integer)
==> Parameters: 测试2(String), 24(Integer), [email protected](String), 1(Integer)
         */
        List<Student>list =new ArrayList<>();
        Student student = new Student();
        student.setName("测试1");
        student.setEmail("[email protected]");
        student.setAge(23);
        student.setStatus(1);
        Student student2 = new Student();
        student2.setName("测试2");
        student2.setEmail("[email protected]");
        student2.setAge(24);
        student2.setStatus(1);
        list.add(student);
        list.add(student2);
        boolean rows = studentService.saveBatch(list);
        System.out.println("rows="+rows);
    }
    @Test
    public void testSaveOrUpdate(){
        /**
         * 执行的sql语句
         * SELECT id,name,age,email,status FROM student WHERE id=8
         * 返回 Total:1
         * 执行的sql语句
         * UPDATE student SET name=?, age=?, email=?, status=? WHERE id=?
         * Parameters: 测试2(String), 22(Integer), [email protected](String), 1(Integer), 8(Integer)
         * 会根据主键先查询,如果存在就更新,不存在就插入
         */
        Student stu = new Student(8,"测试2",22,"[email protected]",1);
        boolean flag = studentService.saveOrUpdate(stu);
        System.out.println("flag="+flag);
    }
    @Test
    public void testSaveOrUpdate2(){
        /**
         * 执行的sql语句
         * SELECT id,name,age,email,status FROM student WHERE id=8
         * 返回 Total:0
         * 执行的sql语句
         * INSERT INTO student ( id, name, age, email, status ) VALUES ( ?, ?, ?, ?, ? )
         * Parameters: 11(Integer), 测试11(String), 11(Integer), [email protected](String), 1(Integer)
         */
        Student stu = new Student(11,"测试11",11,"[email protected]",1);
        boolean flag = studentService.saveOrUpdate(stu);
        System.out.println("flag="+flag);
    }
    @Test
    public void removeById(){
        /**
         * 执行的sql语句
         * DELETE FROM student WHERE id IN ( ? , ? )
         * Parameters: 8(Integer), 9(Integer)
         */
        List<Integer>ids = Arrays.asList(8,9);
        boolean flag = studentService.removeByIds(ids);
        System.out.println("flag="+flag);
    }
}

分页查询

在配置好分页插件之后,分页查询才会生效

package com.example.demo;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@SpringBootTest
public class serviceTest {
    @Resource
    private StudentService studentService;
    @Test
    public void page(){
        /*
           执行的sql语句
           SELECT COUNT(*) AS total FROM student
           SELECT id,name,age,email,status FROM student LIMIT 2
         */
        IPage<Student>iPage =new Page<>(1,2);
        IPage<Student>page = studentService.page(iPage);
        List<Student>list =page.getRecords();
        System.out.println(list);//[Student(id=1, name=丽斯, age=20, [email protected], status=1), Student(id=2, name=李四, age=20, [email protected], status=1)]
        System.out.println(page.getPages());//4
    }
}

条件构造器

package com.example.demo;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@SpringBootTest
public class serviceTest {
    @Resource
    private StudentService studentService;
    @Test
    public void contextLoad(){
        QueryWrapper<Student>queryWrapper=new QueryWrapper<>();
        /*
        select():设置查询字段
        执行的sql语句:
            SELECT id,name,age,email,status FROM student WHERE age=0
         */
        queryWrapper.select("id","name","age","email","status")
        .eq("age",20);
        studentService.list(queryWrapper).forEach(student -> System.out.println(student));
    }
    @Test
    public void updateWrapperTest(){
        UpdateWrapper<Student>updateWrapper =new UpdateWrapper<>();
        updateWrapper.set("age",20)
                .eq("name","张三");
        boolean flag = studentService.update(updateWrapper);
        /*
            执行的sql语句:
            UPDATE student SET age=? WHERE (name = ?)
             Parameters: 20(Integer), 张三(String)
         */
        System.out.println("flag="+flag);

    }

    @Test
    public void queryWrapperTest() {
        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().select(Student::getId, Student::getName, Student::getAge, Student::getEmail, Student::getStatus)
                .eq(Student::getAge, 20);
        studentService.list(queryWrapper).forEach(student -> System.out.println(student));
        /*
        lamda表达式
            执行的sql语句:
             SELECT id,name,age,email,status FROM student WHERE (age = ?)
             Parameters: 20(Integer)
         */
    }
}    

id生成策略

全局id生成策略配置:
在全局配置文件中,配置id生成策略,就不需要在每个实体类上添加主键配置了

mybatis-plus:
  global-config:
    db-config:
      id-type: auto

逻辑删除

物理删除:在删除的时候,直接将数据从数据库中删除
逻辑删除:从逻辑层面控制删除,通常会在表里添加一个逻辑删除的字段比如enabled,is_delete,数据默认是有效的(值为1),当用户删除时将数据修改
update 0,在查询的时候就只查where enabled = 1,
1.需要添加逻辑删除的字段
2.局部单表逻辑删除,需要在对应的pojo类加入对应的逻辑删除标识字段

package com.example.demo.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic //代表逻辑删除
    private Integer status;

}

全局逻辑删除,如果进行了全局逻辑删除配置并且指定了,就可以不用在每个实体类中配置了 @TableLogic

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: status # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

测试
有逻辑删除,mp封装的list()会自动过滤逻辑删除状态为已删除的字段

package com.example.demo;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@SpringBootTest
public class serviceTest {
    @Resource
    private StudentService studentService;
    @Test
    public void logicDel(){
        /**
         * 执行sql语句:
         * UPDATE student SET status=1 WHERE id=1 AND status=0
         */
        studentService.removeById(1);
    }
    @Test
    public void listTest(){
        /**
         * 执行的sql语句
         *  SELECT id,name,age,email,status FROM student WHERE status=0
         */
        List<Student>list=studentService.list();
        list.forEach(student -> System.out.println(student));
    }
}    

数据自动填充

官网介绍

  • 在实体类的属性上添加@TableField(fill = FieldFill.INSERT) ,标记填充字段
package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic //代表逻辑删除
    private Integer status;
    // 创建时间:希望在添加是数据的时候填充:当前时间
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    //修改时间:希望在修改数据的时候填充当前时间
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

}

  • 自定义实现类 MyMetaObjectHandler
package com.example.demo.component;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * mybatis-plus自动填充功能自定义接口
 */
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
      // 插入时:创建时间字段为当前时间
      this.setFieldValByName("createTime",new Date(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 修改时:修改时间字段为当前时间
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

测试

package com.example.demo;

import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class AutoTest {
    @Resource
    private StudentService studentService;
    @Test
    public void test(){
        Student student = new Student();
        student.setName("张三");
        student.setAge(23);
        student.setStatus(0);
        student.setEmail("[email protected]");
        /**
         * 执行sql语句
         *  INSERT INTO student ( name, age, email, status, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )
         *  Parameters: 张三(String), 23(Integer), [email protected](String), 0(Integer), 2021-11-22 21:35:43.928(Timestamp), null
         */
        studentService.save(student);
    }
    @Test
    public void update(){
        /**
         * 执行sql语句
         * PDATE student SET name=?, age=?, email=?, update_time=? WHERE id=? AND status=0
         * Parameters: 张三(String), 22(Integer), [email protected](String), 2021-11-22 21:14:41.971(Timestamp), 1(Integer)
         */
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(22);
        student.setStatus(0);
        student.setEmail("[email protected]");
        boolean flag = studentService.updateById(student);
        System.out.println("flag="+flag);
    }
}

执行 SQL 分析打印

添加maven依赖

 <dependency>
            <groupId>p6spygroupId>
            <artifactId>p6spyartifactId>
            <version>3.9.1version>
        dependency>

mysql中sql分析打印配置

spring:
  datasource:
    #url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    #driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

在这里插入图片描述
在resources目录下添加spy.properties,配置如下:

#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2

执行测试语句

 @Test
    public void update(){
        /**
         * 执行sql语句
         * PDATE student SET name=?, age=?, email=?, update_time=? WHERE id=? AND status=0
         * Parameters: 张三(String), 22(Integer), [email protected](String), 2021-11-22 21:14:41.971(Timestamp), 1(Integer)
         */
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(22);
        student.setStatus(0);
        student.setEmail("[email protected]");
        boolean flag = studentService.updateById(student);
        System.out.println("flag="+flag);
    }

控制台输出,显示当前sql执行所消耗时间
在这里插入图片描述

数据安全保护

防止删库跑路
1.得到16位随机密钥

package com.example.demo;

import com.baomidou.mybatisplus.core.toolkit.AES;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class randomKeyTest {
    @Test
    public void test(){
        String randomKey = AES.generateRandomKey();
    }
}

2.根据密钥加密数据库连接信息

package com.example.demo;

import com.baomidou.mybatisplus.core.toolkit.AES;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class randomKeyTest {
    @Test
    public void test(){
        String randomKey = AES.generateRandomKey();
        String username = AES.encrypt("root",randomKey);
        String pwd = AES.encrypt("root",randomKey);
        System.out.println(username);
        System.out.println(pwd);
    }
}

3.修改配置文件

    username: mpw:3vOuDLOc1ZjXczflw9LCYA==
    password: mpw:3vOuDLOc1ZjXczflw9LCYA==
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver

4.在部署的时候需要解密
java -jar xxx.jar --mpw.key=你的16位随机密钥
官网介绍

乐观锁

官网介绍
mybatis-plus实战学习_第14张图片
1.修改表结构,添加version字段,默认为1
mybatis-plus实战学习_第15张图片
2.在实体类的字段上加上@Version注解

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic //代表逻辑删除
    private Integer status;
    // 创建时间:希望在添加是数据的时候填充:当前时间
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    //修改时间:希望在修改数据的时候填充当前时间
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    @Version
    private Integer version;

}

3.配置乐观锁插件

package com.example.demo.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Configuration标注的类相当于xml配置文件
 */
@Configuration
public class Config {
    /**
     * 定义方法,方法的返回值是java对象,这个对象是放入到spring容器中
     *  @Bean 等同于
     */
    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        // 添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

}

测试

package com.example.demo;

import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class StudentVersionTest {
    @Resource
    private StudentService studentService;
    @Test
    public void testCAS(){
        // 线程1 age:50,version:1
        Student student1 = studentService.getById(1);
        student1.setAge(50);
        //线程2 age:100 version:1
        Student student2 = studentService.getById(1);
        student2.setAge(100);
        //update 50 version:2 where version1 = 数据库version
        System.out.println(studentService.updateById(student1));/true
        //update 100 version:2 where version1 = 数据库version
        System.out.println(studentService.updateById(student2));//false
        if(studentService.updateById(student1)){
            System.out.println("更新成功");
        }
        if(studentService.updateById(student2)){
            System.out.println("更新失败,请重新刷新页面并更新");
        }
    }
}

更新时候,需要设置version字段

代码生成器

官网教程
引入依赖

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-generatorartifactId>
            <version>3.5.1version>
        dependency>

Generator源码地址
GitHub
Gitee
官方文档
Maven仓库坐标

快速入门

maven依赖


<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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.5.6version>
        <relativePath/> 
    parent>
    <groupId>com.examplegroupId>
    <artifactId>demoartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>demoname>
    <description>Demo project for Spring Bootdescription>
    <properties>
        <java.version>1.8java.version>
    properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.2.8version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.27version>
        dependency>
        
        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.4.3.4version>
        dependency>
        
        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-generatorartifactId>
            <version>3.5.1version>
        dependency>
        
        
        <dependency>
            <groupId>org.apache.velocitygroupId>
            <artifactId>velocity-engine-coreartifactId>
            <version>2.3version>
        dependency>
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.22version>
            <scope>providedscope>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
    <pluginRepositories>
        <pluginRepository>

            <id>alimaven spring pluginid>

            <name>alimaven spring pluginname>

            <url>https://maven.aliyun.com/repository/spring-pluginurl>

        pluginRepository>
    pluginRepositories>

project>

package com.example.demo.builder;

import lombok.Getter;
import lombok.Setter;

/**
 * 测试构建者模式代码生成器
 */
@Setter
@Getter
public class CodeGenerator {
    /**
     * 数据源配置
     */
    private String datasource;
    /**
     * 包配置
     */
    private String packageConfig;
    /**
     * 策略配置
     */
    private String strategyConfig;

    /**
     * 执行代码生成
     */
    public void execute(){
        System.out.println(datasource+" "+packageConfig+" "+strategyConfig);
    }
}

package com.example.demo.builder;

/**
 * 代码生成器构建者模式
 */
public class CodeGeneratorBuilder {
    private CodeGenerator codeGenerator;
    public CodeGeneratorBuilder(CodeGenerator codeGenerator){
        this.codeGenerator=codeGenerator;
    }
    public static CodeGeneratorBuilder create(String datasource){
        CodeGenerator cg = new CodeGenerator();
        cg.setDatasource(datasource);
        return new CodeGeneratorBuilder(cg);
    }
    public  CodeGeneratorBuilder packageConfig(String packageConfig){
        codeGenerator.setPackageConfig(packageConfig);
        return this;
    }
    public  CodeGeneratorBuilder strategyConfig(String strategyConfig){
        this.codeGenerator.setStrategyConfig(strategyConfig);
        return this;
    }
    public void execute(){
        codeGenerator.execute();
    }
}

测试

package com.example.demo.builder;

public class Test {
    public static void main(String[] args) {
        //普通模式
        CodeGenerator codeGenerator = new CodeGenerator();
        codeGenerator.setDatasource("mysql");
        codeGenerator.setPackageConfig("com.baomidou");
        codeGenerator.setStrategyConfig("驼峰命名");
        codeGenerator.execute();
        //构建者模式
        CodeGeneratorBuilder.create("mysql").packageConfig("com.baomidou").strategyConfig("驼峰命名").execute();

    }
}

输出
mybatis-plus实战学习_第16张图片

代码生成器(3.5.1+版本)快速入门

数据表创建语句

drop table if exists `t_simple`;
create table `t_simple`
(
    id          int  primary key  auto_increment comment 'id',
    name        varchar(50) comment '姓名',
    age         int comment '年龄',
    delete_flag tinyint(1) comment '删除标识1',
    deleted tinyint(1) comment '删除标识2',
    version     bigint comment '版本',
    create_time datetime comment '创建时间',
    update_time datetime comment '更新时间'
) COMMENT = '测试表';
package com.example.demo.generator;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;

public class CodeGenerator {
    static final String URL = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8";

    public static void main(String[] args) {
        FastAutoGenerator.create(URL, "root", "root")
                // 全局配置
                .globalConfig(builder -> builder.outputDir("D:\\code"))
                // 策略配置
                .strategyConfig(builder -> builder.addInclude("t_simple"))
                /*
               模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
              .templateEngine(new BeetlTemplateEngine())
              .templateEngine(new FreemarkerTemplateEngine())
            */
                //执行
                .execute();
    }
}

输出实体类,Mapper,Service,Controller如下

package com.baomidou.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 

* 测试表 *

* * @author 作者 * @since 2021-11-29 */
@TableName("t_simple") public class TSimple implements Serializable { private static final long serialVersionUID = 1L; /** * id */ @TableId(value = "id", type = IdType.AUTO) private Integer id; /** * 姓名 */ private String name; /** * 年龄 */ private Integer age; /** * 删除标识1 */ private Boolean deleteFlag; /** * 删除标识2 */ private Boolean deleted; /** * 版本 */ private Long version; /** * 创建时间 */ private LocalDateTime createTime; /** * 更新时间 */ private LocalDateTime updateTime; 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 Boolean getDeleteFlag() { return deleteFlag; } public void setDeleteFlag(Boolean deleteFlag) { this.deleteFlag = deleteFlag; } public Boolean getDeleted() { return deleted; } public void setDeleted(Boolean deleted) { this.deleted = deleted; } public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; } public LocalDateTime getCreateTime() { return createTime; } public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; } public LocalDateTime getUpdateTime() { return updateTime; } public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; } @Override public String toString() { return "TSimple{" + "id=" + id + ", name=" + name + ", age=" + age + ", deleteFlag=" + deleteFlag + ", deleted=" + deleted + ", version=" + version + ", createTime=" + createTime + ", updateTime=" + updateTime + "}"; } }
package com.baomidou.mapper;

import com.baomidou.entity.TSimple;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * 

* 测试表 Mapper 接口 *

* * @author 作者 * @since 2021-11-29 */
public interface TSimpleMapper extends BaseMapper<TSimple> { }

DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baomidou.mapper.TSimpleMapper">

mapper>

package com.baomidou.service;

import com.baomidou.entity.TSimple;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * 

* 测试表 服务类 *

* * @author 作者 * @since 2021-11-29 */
public interface ITSimpleService extends IService<TSimple> { }
package com.baomidou.service.impl;

import com.baomidou.entity.TSimple;
import com.baomidou.mapper.TSimpleMapper;
import com.baomidou.service.ITSimpleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * 

* 测试表 服务实现类 *

* * @author 作者 * @since 2021-11-29 */
@Service public class TSimpleServiceImpl extends ServiceImpl<TSimpleMapper, TSimple> implements ITSimpleService { }
package com.baomidou.controller;


import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;

/**
 * 

* 测试表 前端控制器 *

* * @author 作者 * @since 2021-11-29 */
@Controller @RequestMapping("/tSimple") public class TSimpleController { }

官网代码生成器(3.5.1+)

package com.example.demo.generator;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;

import java.util.Collections;

public class CodeGenerator {
    static final String URL = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";

    public static void main(String[] args) {
        FastAutoGenerator.create(URL, "root", "root")
                .globalConfig(builder -> {
                    builder.author("baomidou") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("D://"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.baomidou.mybatisplus.samples.generator") // 设置父包名
                            .moduleName("system") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("t_simple") // 设置需要生成的表名
                            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                }).execute();
    }
}

文件夹格式
mybatis-plus实战学习_第17张图片
实体类

package com.baomidou.mybatisplus.samples.generator.system.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/**
 * 

* 测试表 *

* * @author baomidou * @since 2021-11-29 */
@TableName("t_simple") @ApiModel(value = "Simple对象", description = "测试表") public class Simple implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty("id") @TableId(value = "id", type = IdType.AUTO) private Integer id; @ApiModelProperty("姓名") private String name; @ApiModelProperty("年龄") private Integer age; @ApiModelProperty("删除标识1") private Boolean deleteFlag; @ApiModelProperty("删除标识2") private Boolean deleted; @ApiModelProperty("版本") private Long version; @ApiModelProperty("创建时间") private LocalDateTime createTime; @ApiModelProperty("更新时间") private LocalDateTime updateTime; 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 Boolean getDeleteFlag() { return deleteFlag; } public void setDeleteFlag(Boolean deleteFlag) { this.deleteFlag = deleteFlag; } public Boolean getDeleted() { return deleted; } public void setDeleted(Boolean deleted) { this.deleted = deleted; } public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; } public LocalDateTime getCreateTime() { return createTime; } public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; } public LocalDateTime getUpdateTime() { return updateTime; } public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; } @Override public String toString() { return "Simple{" + "id=" + id + ", name=" + name + ", age=" + age + ", deleteFlag=" + deleteFlag + ", deleted=" + deleted + ", version=" + version + ", createTime=" + createTime + ", updateTime=" + updateTime + "}"; } }

数据库配置

  • 添加指定数据库驱动依赖jar
  • 数据库网络可用,云主机注意!防火墙、网络安全组对应端口是否开放
  • 严禁使用数据库关键词命名
  • 务必表字段添加注释
  • 多schema非默认必须指定
    查询数据库中某张表的字段
    mybatis-plus实战学习_第18张图片
    查询当前数据库中的表
    mybatis-plus实战学习_第19张图片

包配置

  • 生成当前项目目录
  • System.getProperty(“user.dir”)+“src/main/java”
  • 定义父目录 parent - 自定义输出pathInfo
  • 模块化输出指定parent动态路径

你可能感兴趣的:(java,mybatis)