mybatis-plus之插件

Posted 晚安果汁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis-plus之插件相关的知识,希望对你有一定的参考价值。

一、插件机制。

1、mybatis允许你在已映射语句执行过程中的某一点进行拦截调用,默认情况下,mybatis允许使用插件来拦截的方法调用包括:executor(update,query,commit,rollback)等,parameterhandler,resultsethandler,statementhandler。

总体概括为:拦截执行器的方法, 拦截参数的处理,拦截结果集的处理,拦截SQL语法构建的处理。

2、示例。

二、执行分析插件。

在MP中提供了对SQL执行的分析的插件,可用作阻断全表更新、删除的操作,注意:该插件仅适用于开发环境,不适用于生产环境。

1、配置springboot:SQL分析插件

2、测试。

 SQL

三、性能分析插件。

性能分析拦截器,用于输出每条SQL语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常,该插件只用于开发环境,不建议生产环境使用。

1、配置方式一

2、配置方式二 

 3、测试 

 SQL语句展示

时间展示

四、乐观锁插件。

当要更新一条记录的时候,希望这条记录没有被别人更新。

1、乐观锁实现方式。

取出记录时,获取当前version。

更新时,带上这个version。

执行更新时,set version = newVersion where version = oldVersion

如果执行version不对,就更新失败

2、配置

mybatis全局配置文件做配置。

 3、在实体类添加version字段。

 4、在数据库添加version字段

 5、测试

 SQL:乐观锁添加了version和id

 避免同时做修改

 数据库改了版本,是不可以改的,避免同时修改数据带来的不安全

特别说明:

1、支持的数据类型有:int、integer、long、Long、date、timestamp、LocalDateTime

2、整数类型下:newVersion = oldVersion + 1

3、newVersion会回写到entity中。

4、仅支持updateById(id)与update(entity,wrapper)方法。

5、在update(entity,wrapper)方法下,wrapper不能复用。

Mybatis插件之Mybatis-Plus的CRUD方法

使用Mybatis-plus进行基本的CRUD(增查改删)操作。

 

实体类(User)代码:

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.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@TableName("tb_user")
public class User {
    @TableId(type = IdType.AUTO) // 需要指定,否则无法新增后拿到回调的id,以及进行删除等操作
    // 查询的时候不需要查出来的字段,默认true,和@TableId作用在同一个字段上时失效
    @TableField(select = false)
    private Integer uid;
    private String uname;
    // 用来解决数据库中的字段和实体类的字段不匹配问题
    @TableField(value = "age",select = false)
    private Integer uage;   // 数据库中的字段为age
    // 用来解决实体类中有的属性但是数据表中没有的字段
    @TableField(exist = false)  // 默认为true
    private String address; // 这是一个数据库中不存在的字段

    public User(String uname, Integer age) {
        this.uname = uname;
        this.uage = age;
    }
}

1、增加操作:

代码如下:直接传入一个实体即可完成

@Test
public void test02(){   // 插入一条记录
    // 1.构建要插入的对象
    User user = new User();
    user.setUname("zhangsan");
    user.setUage(40);
    // 数据库中不存在的字段,通过@TableField(exist = false)排除之
    user.setAddress("beijing");
    // 2.执行添加   返回值为受影响的行数
    int result = userMapper.insert(user);
    System.out.println("受影响的行数=" + result);
    System.out.println("拿到自增的id=" + user.getUid());
}

 

2、更新操作:

方法一:int updateById(T entity);

测试代码:

@Test
public void test04(){   // 根据id进行更新
    // 1.构建更新的对象
    User user = new User();
    // 2.根据id来进行更新
    user.setUid(1007);
    // 3.更新的内容值
    user.setUname("小莉");
    user.setUage(17);
    // 4.执行更新
    int result = userMapper.updateById(user);
    System.out.println("受影响的行数=" + result);
}

方法二:

1-使用QueryWrapper,它只负责条件的匹配

测试代码:

@Test
public void test05(){  // 第一种:使用QueryWrapper,根据条件进行更新
    // 1.设置更新的内容值
    User user = new User();
    user.setUname("王五");
    user.setUage(45);
    // 2.设置更新的匹配条件,可以叠加多个,类似于and
    QueryWrapper<User> wapper = new QueryWrapper<>();
    // 参数1:数据库中的字段名  参数2:字段名的值(匹配的值)
    // 解读:把数据库中uid字段为1015和1016的值修改成user中的内容
    wapper.eq("uid",1015);
    wapper.or();    // 在查询中拼接or
    wapper.eq("uid",1016);
    // 语句还原:UPDATE tb_user SET uname=\'王五\', age=45 WHERE uid = 1015 OR uid = 1016
    // 3.开始更新,参数1:更新的内容   参数2:更新的匹配条件
    int result = userMapper.update(user, wapper);
    System.out.println("受影响的行数=" + result); // 2
}

2-使用UpdateWrapper进行更新操作

测试代码:

@Test
public void test06(){ // 第二种:使用UpdateWrapper,根据条件进行更新
    // 1.定义一个UpdateWrapper对象
    UpdateWrapper<User> wrapper = new UpdateWrapper<>();
    // 2.设置参数
    // set(String column, Object val),参数1:数据库中的字段名  参数2:修改后的值
    // eq(String column, Object val),参数1:数据库中的字段名  参数2:修改条件
    // or(),使查询条件变成用or拼接
    wrapper.set("uname","第五人格").set("age",28)
            .eq("uid",1018).or().eq("uid",1019);
    // 3.执行修改,使用UpdateWrapper,参数1指定为 null
    int result = userMapper.update(null, wrapper);
    System.out.println("受影响的行数=" + result); // 2
    // SQL:UPDATE tb_user SET uname=?,age=? WHERE uid = ? OR uid = ?
}

注意两个条件直接如果要用OR拼接,则需要在两个条件之家插入or()方法。

 

 

3、删除操作:

1-根据id来删除

@Test
public void test03(){
    // 1.直接根据id进行删除
    int result = userMapper.deleteById(1014);
    System.out.println("受影响的行数=" + result); // 1
}

2-根据map条件进行删除

@Test
public void test07(){   // 根据Map来进行删除,多条件之间是and关系
    // 1.构建删除条件map
    Map<String,Object> map = new HashMap<>();
    // 2.设置删除条件的值,参数1:数据库中的字段名,参数2:条件值
    map.put("uname","艾玛x");
    map.put("age",80);
    // 3.执行删除
    int result = userMapper.deleteByMap(map);
    System.out.println("受影响的行数=" + result); // 1
    // SQL:DELETE FROM tb_user WHERE uname = ? AND age = ?
}

3-根据查询条件Wrapper进行删除:delete(Wrapper<T> wrapper)

使用QueryWrapper进行删除,测试代码:

@Test
public void test08(){
    // 1.构建一个QueryWrapper对象
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 2.为QueryWrapper对象设置条件
    wrapper.eq("uid",1010).eq("uname","小柳")
            // 也可以设置OR条件
            .or().eq("uid",1015);
    // 3.执行删除
    int result = userMapper.delete(wrapper);
    System.out.println("受影响的行数=" + result); // 2
    // SQL:DELETE FROM tb_user WHERE uid = ? AND uname = ? OR uid = ? 
}

4-根据id集合实现批量删除:deleteBatchIds(Collection idList)

测试代码:

@Test
public void test09(){
    // 根据集合进行删除(使用的是SQL中的in关键字)
    // 1.构建一个存放id列表的集合
    List<Integer> idList = new ArrayList<>();
    // 2.存放要进行删除的id,存放了3个id
    idList.add(1021);
    idList.add(1022);
    idList.add(1023);
    // 3.执行删除
    int result = userMapper.deleteBatchIds(idList);
    System.out.println("受影响的行数=" + result); // 3
    // SQL:DELETE FROM tb_user WHERE uid IN ( ? , ? , ? )
}

以上就是BaseMapper中增删改操作的方法。

 

接下来,介绍其查询方法,MybatisPlus(MP)提供了多种查询操作,包括根据id查询,批量查询、单挑记录查询、查询列表、分页查询等操作。

4、查询操作

1-根据id查询单个记录

测试代码:

@Test
public void test01(){// 根据id进行查询
    // 1.执行查询操作
    User user = userMapper.selectById(1018);
    // 2.输出查询结果
    System.out.println(user);
}

如果出现以下情况,则需要指定@TableId

 

2-根据id集合列表查询多个记录:selectBatchIds(Collection idList)

测试代码:

@Test
public void test02(){// 根据id集合进行批量查询
    // 1.创建id列表并赋值
    List<Integer> ids = new ArrayList<>();
    ids.add(1016);
    ids.add(1017);
    ids.add(1018);
    // 2.执行查询
    List<User> users = userMapper.selectBatchIds(ids);
    // 3.遍历查询结果集
    for (User user : users) {
        // 4.打印查询结果
        System.out.println(user);
    }
    // SQL:SELECT uid,uname FROM tb_user WHERE uid IN ( ? , ? , ? ) 
}

3-根据条件进行查询,用map来封装查询条件

测试代码:

@Test
public void test03(){
    // 1.构建查询条件
    Map<String, Object> map = new HashMap<>();
    map.put("uname","第五人格");
    map.put("age",28);  // 多个条件之间的SQL用and拼接
    // 2.执行查询
    List<User> users = userMapper.selectByMap(map);
    // 3.打印输出
    printUsers(users);
    // SQL:SELECT uid,uname FROM tb_user WHERE uname = ? AND age = ? 
}

4-查询单挑记录,若返回加过大于一个,抛出异常MybatisSystemException

测试代码:

@Test
public void test04(){   // 查询单条记录
    // 1.定义查询条件对象
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 2.设置查询条件
    wrapper.eq("uname","第五人格");
    // 查询的记录>1个时,抛出异常MyBatisSystemException
    User user = userMapper.selectOne(wrapper);
    // 3.打印结果
    System.out.println(user);
// SQL:SELECT uid,uname FROM tb_user WHERE uname = ?
}

5-查询符合条件的记录数,Integer selectCount(Wrapper<User> queryWrapper)

测试代码:

@Test
public void test05(){ // 查询记录数,类似于conut(*)
    // 若需要设置条件可使用Wrapper对象,null表示查询所有
    Integer count = userMapper.selectCount(null);
    // 打印返回的记录数
    System.out.println("记录数有 = " + count);
    // SQL:SELECT COUNT( 1 ) FROM tb_user
}

6-查询符合条件的记录列表,List<User> selectList(Wrapper<User> queryWrapper)

若参数为null,则为查询所有

测试代码:

@Test
public void test06(){//根据查询条件查询列表
    // 1.构建一个QueryWrapper对象
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 2.设置条件,参数1:数据库字段名,参数2:参数值
    wrapper.eq("uname","第五人格");
    // 3.执行查询
    List<User> users = userMapper.selectList(wrapper);
    //List<User> users = userMapper.selectList(null);// 查询所有
    // 4.打印结果
    printUsers(users);
}

7-根据条件把查询结果封装在Map和List中

List<Map<String, Object>> selectMaps(Wrapper<User> queryWrapper)

测试代码:

@Test
public void test07(){
    List<Map<String, Object>> maps = userMapper.selectMaps(null);
    for (Map<String, Object> map : maps) {
        // 一个map对应一条记录
        // 每个map的key都为字段名
        // 每个map的值都为字段具体值
        System.out.println(map);
    }
}

8-分页查询

首先定义一个新的类为配置类(MybatisPlusConfig)

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

@Configuration
public class MybatisPlusConfig {

    // 分页插件
    @Bean   // 注入Spring容器中
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }
}

之后开始测试,代码如下:

@Test
public void test09(){   // 测试分页
    // 1.查询条件,null则为查询所有
    Wrapper<User> wrapper = null;
    // 1.1 使用其构造,参数1:当前页,参数2:每页的大小
    Page<User> page = new Page<>(1,2);
    // 2.执行查询
    // 参数1:为接口Ipage,其实现类只有一个Page,参数2:为查询条件,返回一个Ipage对象
    IPage<User> userIPage = userMapper.selectPage(page, wrapper);
    // 3.打印重要参数
    System.out.println("总页数= " + userIPage.getPages());
    System.out.println("总记录数= " + userIPage.getTotal());
    System.out.println("页面大小= " + userIPage.getSize());
    System.out.println("当前页= " + userIPage.getCurrent());
    System.out.println("查询结果如下:" );
    // 4.打印分页结果
    for (User user : userIPage.getRecords()) {
        System.out.println(user);
    }
    // SQL:SELECT uid,uname,age AS uage FROM tb_user LIMIT ?,? 
}

 

至此,关于BaseMapper接口中的所有方法都已经测试完成了!

 

以上是关于mybatis-plus之插件的主要内容,如果未能解决你的问题,请参考以下文章

mybatis-plus之插件

Mybatis插件之Mybatis-Plus的实体类注解篇

Mybatis-Plus:插件(mybatis的插件机制执行分析插件性能分析插件乐观锁插件)

mybatis-plus小课堂:多表查询案例篇(apply 拼接 in SQL,来查询从表某个范围内的数据)

MyBatis-Plus03_分页插件自定义分页

浅谈MyBatis-Plus学习之插件扩展