MyBatis-Plus in-depth - conditional constructor and plug-in management

Preface

        In the previous article, Lizhi sorted out the basic use, configuration and general service interface of MyBatis-Plus. We found that with the auxiliary enhancement of MyBatis-Plus, we no longer need to configure the sql statement in the xml file to implement basic sql. After using it, it is indeed the best partner! In this article, Lizhi will focus on sorting out two knowledge points about MyBatis-Plus: conditional constructor, paging plug-in and optimistic lock plug-in. I hope it will be helpful to friends in need~~~


Article directory

Preface

1. Conditional constructor

1.1 Assembling query conditions

1.2 Assembly and sorting conditions

1.3 Assembling deletion conditions

1.4 Use QueryWrapper to implement modification functions 

1.5 Condition priority

1.6 Subquery

1.7 Use UpdateWrapper to implement modification functions

1.8 Use Condition to assemble conditions

1.9 LambdaQueryWrapper

1.10 LambdaUpdateWrapper 

2. Pagination plug-in

2.1 Basic use 

2.2 Custom paging plug-in 

3. Optimistic lock plug-in

3.1 Optimistic locking and pessimistic locking

3.2 Optimistic lock plug-in

Summarize


1. Conditional constructor

        The conditional constructor, as the name suggests, is used to encapsulate the current conditions we use to query. The top-level interface of the conditional constructor is Mapper, which is inherited by AbstractWrapper. It consists of three subclasses: AbstractLambdaWrapper, UpdateWrapper and QueryWrapper.

1.1 Assembling query conditions

//条件构造器组装查询条件
    @Test
    public void testWrapper(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name","crj")
                .between("age",20,30)
                .isNotNull("email");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.2 Assembly and sorting conditions

//组装排序条件
    @Test
    public void test1(){
        //查询用户信息按照年龄的降序排序,若年龄相同则按照id升序排序
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age")
                .orderByAsc("uid");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.3 Assembling deletion conditions

//组装删除条件
    @Test
    public void test2(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println("受影响函数"+result);
    }

1.4 Use QueryWrapper to implement modification functions 

//实现修改功能
    @Test
    public void  test3(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //把年龄大于20且姓名为crj或者是邮箱为null的用户信息进行修改
        queryWrapper.gt("age",20)
                .like("user_name","crj")
                .or()
                .isNull("email");
        User user = new User();
        user.setName("CRJ");
        user.setEmail("[email protected]");
        int result = userMapper.update(user,queryWrapper);
        System.out.println(result);
    }

1.5 Condition priority

Priority operations are implemented through Lambda expressions in and() and or(), where the conditions in the Lambda expression are executed first.

 //条件优先级
    @Test
    public  void test4(){
        //将用户名中含有crj并且(年龄大于20或邮箱为null)的用户信息修改
        //lambda中的条件优先执行
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name","crj")
                .and(i->i.gt("age",20).or().isNull("email"));
        User user = new User();
        user.setName("CRJ");
        user.setEmail("[email protected]");
        int result = userMapper.update(user,queryWrapper);
        System.out.println(result);
    }

1.6 Subquery

//子查询
    @Test
    public void test5(){
        //查询id小于等于100的用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("uid","select uid from t_user where uid<=100");
        List<User> list = userMapper.selectList(queryWrapper);
    }

1.7 Use UpdateWrapper to implement modification functions

//使用UpdateWrapper实现修改功能
//将用户名中含有crj并且(年龄大于20或邮箱为null)的用户信息修改
    @Test
    public  void  test6(){
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.like("user_name","crj")
                .and(i->i.gt("age",20).or().isNull("email"));
        updateWrapper.set("user_name","CRJ");
        userMapper.update(null,updateWrapper);
    }

1.8 Use Condition to assemble conditions

1.9 LambdaQueryWrapper

    @Test
    public void test8(){
        String username = "a";
        Integer ageBegin = null;
        Integer ageEnd = 30;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
                .ge(ageBegin!=null,User::getAge,ageBegin)
                .le(ageEnd!=null,User::getAge,ageEnd);
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.10 LambdaUpdateWrapper 

    @Test
    public  void  test9(){
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.like(User::getName,"crj")
                .and(i->i.gt(User::getAge,20).or().isNull(User::getEmail));
        updateWrapper.set(User::getName,"CRJ");
        userMapper.update(null,updateWrapper);
    }

2. Pagination plug-in

2.1 Basic use 

Configuration class  for paging plugin

package com.crj.mybatisplus_test.config;

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

//配置类,配置MyBatisPlus的插件功能
@Configuration
@MapperScan("com.crj.mybatisplus_test.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

Test class

package com.crj.mybatisplus_test;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crj.mybatisplus_test.mapper.UserMapper;
import com.crj.mybatisplus_test.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class MyBatisPlusPluginsTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void test1(){
        Page<User> page = new Page<>(1,3);
        userMapper.selectPage(page,null);
        System.out.println(page);
    }
}

Several methods of page object:

  • page.getRecords(): Get the current page data
  • page.getCurrent(): Get the page number of the current page
  • page.getSize(): Get the number of items displayed on each page
  • page.getPages(): Get the total number of pages
  • page.getTotal(): Get the total number of records
  • page.hasNext(): Check if there is a next page
  • page.hasPrevious(): Check if there is a previous page

Configuration type alias:

mybatis-plus:

        type-aliases-package: full path 

2.2 Custom paging plug-in 

        Previously, we used conditional constructors to implement paging operations. By looking at the source code, we know that selectPage requires two parameters. The return value and the first parameter are both of IPage type, and the IPage type interface is implemented by the Page class object, so the first One parameter must be a page object. We need to handwrite a method in the userMapper interface to replace the original selectPage. At the same time, the configuration file of the paging plug-in remains unchanged, and the plug-in function of MyBatisPlus is configured.

UserMapper.java 

package com.crj.mybatisplus_test.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crj.mybatisplus_test.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;


@Repository
//继承MyBatis-Plus的BaseMapper接口
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据年龄查询用户信息并分页
     * @param page mybatis-plus提供的分页对象,必须放在第一个参数中
     * @param age
     * @return
     */
    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
}

UserMapper.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.crj.mybatisplus_test.mapper.UserMapper">

<!--    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);-->
    <select id="selectPageVo" resultType="User">
        select uid,name,age from t_user where age > #{age}
    </select>
</mapper>

Test class

    @Test
    public void testPageVo(){
        Page<User> page = new Page<>(1,3);
        userMapper.selectPageVo(page,20);
    }

3. Optimistic lock plug-in

3.1 Optimistic locking and pessimistic locking

        Speaking of optimistic locking and pessimistic locking, we often understand it through a scenario: we need to perform a +10 operation and then a -30 operation on a number with a value of 100. These two steps are executed using multi-threads. Threads A and B take a number C with a value of 100 at the same time. A performs a +10 operation on C, and B performs a -30 operation on the retrieved value. If there is no lock control, then the value D processed by A cannot be taken by B. arrives and will be covered by B. There are two types of locking: optimistic locking and pessimistic locking. Pessimistic locking will pay special attention to thread safety, and the value of B can only be obtained after A completes the operation; while optimistic locking uses version control to detect whether C is edited.

Unlocked scene simulation

Entity class

package com.crj.mybatisplus_test.pojo;

import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    private Integer version;

}

mapper interface

package com.crj.mybatisplus_test.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.springframework.stereotype.Service;

@Service
public interface ProductMapper extends BaseMapper<Product> {

}

Test class

package com.crj.mybatisplus_test;

import com.crj.mybatisplus_test.mapper.ProductMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

//乐观锁插件使用
@SpringBootTest
public class MyBatisLockTest {
    @Autowired
    private ProductMapper productMapper;
    //模拟线程场景
    @Test
    public void test1(){
        Product productA = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productA.getPrice());
        Product productB = productMapper.selectById(1);
        System.out.println("B查询的商品价格"+productB.getPrice());

        productA.setPrice(productA.getPrice()+10);
        productMapper.updateById(productA);
        productB.setPrice(productB.getPrice()-30);
        productMapper.updateById(productB);
        //最后结果
        Product productC = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productC.getPrice());

    }
}

3.2 Optimistic lock plug-in

As we know earlier, the implementation of optimistic locking needs to be controlled by adding a version number, so the entity class needs to set the version number through @Version.

Entity class

package com.crj.mybatisplus_test.pojo;

import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;

    @Version //标识乐观锁版本号字段
    private Integer version;

}

MyBatis-Plus plug-in configuration class

The optimistic lock plug-in method OptimisticLockerInnerInterceptor() needs to be configured in the configuration class

package com.crj.mybatisplus_test.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.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//配置类,配置MyBatisPlus的插件功能
@Configuration
@MapperScan("com.crj.mybatisplus_test.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //配置分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //配置乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

Test class

It should be noted that B needs to retry after failing to modify the data to complete the task requirements. 

package com.crj.mybatisplus_test;

import com.crj.mybatisplus_test.mapper.ProductMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

//乐观锁插件使用
@SpringBootTest
public class MyBatisLockTest {
    @Autowired
    private ProductMapper productMapper;
    //模拟线程场景
    @Test
    public void test1(){
        Product productA = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productA.getPrice());
        Product productB = productMapper.selectById(1);
        System.out.println("B查询的商品价格"+productB.getPrice());

        productA.setPrice(productA.getPrice()+10);
        productMapper.updateById(productA);
        productB.setPrice(productB.getPrice()-30);
        int result = productMapper.updateById(productB);

        //由于加入了版本号控制,因此需要对修改失败的操作进行重试
        if(result==0){
            //失败重试
            Product productNew = productMapper.selectById(1);
            productNew.setPrice(productNew.getPrice()-30);
            productMapper.updateById(productNew);
        }
        //最后结果
        Product productC = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productC.getPrice());

    }
}

Summarize

        Through several basic usage examples of conditional constructors, Lizhi has a relatively intuitive understanding of the use of the wrapper class. At the same time, Lizhi feels that what needs more attention is the use of two plug-ins. In the next article, Lizhi will finish the basic knowledge related to MyBatis-Plus, and at the same time try to integrate it into the learning project. Let’s look forward to it together with Lizhi, hahahahaha~~~

Today has become the past, but we still look forward to the future tomorrow! I am Xiaolizhi, and I will accompany you on the road of technological growth. Coding is not easy, so please raise your little paw and give me a thumbs up, hahaha~~~ Bixinxin♥~~~

Guess you like

Origin blog.csdn.net/qq_62706049/article/details/132655553