在前面的文章中,荔枝梳理了一个MyBatis-Plus的基本使用、配置和通用Service接口,我们发现在MyBatis-Plus的辅助增强下我们不再需要通过配置xml文件中的sql语句来实现基本的sql操作了,不愧是最佳搭档!在这篇文章中,荔枝会着重梳理有关MyBatis-Plus的两个知识点:条件构造器、分页插件和乐观锁插件,希望对有需要的小伙伴有帮助~~~
条件构造器,顾名思义就是用来封装当前我们用来查询的条件的,条件构造器的最顶层的接口是Mapper,被AbstractWrapper继承,其下由三个子类分别是:AbstractLambdaWrapper、UpdateWrapper和QueryWrapper。

- //条件构造器组装查询条件
- @Test
- public void testWrapper(){
- QueryWrapper
queryWrapper = new QueryWrapper<>(); - queryWrapper.like("user_name","crj")
- .between("age",20,30)
- .isNotNull("email");
- List
list = userMapper.selectList(queryWrapper); - list.forEach(System.out::println);
- }
- //组装排序条件
- @Test
- public void test1(){
- //查询用户信息按照年龄的降序排序,若年龄相同则按照id升序排序
- QueryWrapper
queryWrapper = new QueryWrapper<>(); - queryWrapper.orderByDesc("age")
- .orderByAsc("uid");
- List
list = userMapper.selectList(queryWrapper); - list.forEach(System.out::println);
- }
- //组装删除条件
- @Test
- public void test2(){
- QueryWrapper
queryWrapper = new QueryWrapper<>(); - queryWrapper.isNull("email");
- int result = userMapper.delete(queryWrapper);
- System.out.println("受影响函数"+result);
- }
- //实现修改功能
- @Test
- public void test3(){
- QueryWrapper
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("123456@123.com");
- int result = userMapper.update(user,queryWrapper);
- System.out.println(result);
- }
在and()和or()中通过Lambda表达式实现优先级操作,其中Lambda表达式中的条件优先执行。
- //条件优先级
- @Test
- public void test4(){
- //将用户名中含有crj并且(年龄大于20或邮箱为null)的用户信息修改
- //lambda中的条件优先执行
- QueryWrapper
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("123456@123.com");
- int result = userMapper.update(user,queryWrapper);
- System.out.println(result);
- }
- //子查询
- @Test
- public void test5(){
- //查询id小于等于100的用户信息
- QueryWrapper
queryWrapper = new QueryWrapper<>(); - queryWrapper.inSql("uid","select uid from t_user where uid<=100");
- List
list = userMapper.selectList(queryWrapper); - }
- //使用UpdateWrapper实现修改功能
- //将用户名中含有crj并且(年龄大于20或邮箱为null)的用户信息修改
- @Test
- public void test6(){
- UpdateWrapper
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);
- }

- @Test
- public void test8(){
- String username = "a";
- Integer ageBegin = null;
- Integer ageEnd = 30;
- LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
- .ge(ageBegin!=null,User::getAge,ageBegin)
- .le(ageEnd!=null,User::getAge,ageEnd);
- List
list = userMapper.selectList(queryWrapper); - list.forEach(System.out::println);
- }
- @Test
- public void test9(){
- LambdaUpdateWrapper
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);
- }
分页插件的配置类
- 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;
- }
- }
测试类
- 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
page = new Page<>(1,3); - userMapper.selectPage(page,null);
- System.out.println(page);
- }
- }
page对象的几个方法:
配置类型别名:
mybatis-plus:
type-aliases-package:全路径
之前借助条件构造器来实现分页的操作,通过查看源码知晓,selectPage要求两个参数,返回值和第一个参数都是IPage类型的,而IPage类型的接口是被Page类对象实现的,因此第一个参数一定是page对象。我们需要在userMapper接口中手写一个方法替代原来的selectPage,同时分页插件的配置文件保持不变,配置好MyBatisPlus的插件功能

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
{ -
- /**
- * 根据年龄查询用户信息并分页
- * @param page mybatis-plus提供的分页对象,必须放在第一个参数中
- * @param age
- * @return
- */
- Page
selectPageVo(@Param("page") Page page,@Param("age") Integer age) ; - }
UserMapper.xml
- "1.0" encoding="UTF-8" ?>
- 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">
-
- <select id="selectPageVo" resultType="User">
- select uid,name,age from t_user where age > #{age}
- select>
- mapper>
测试类
- @Test
- public void testPageVo(){
- Page
page = new Page<>(1,3); - userMapper.selectPageVo(page,20);
- }
说到乐观锁和悲观锁,我们经常通过一个场景来理解:我们需要对一个值为100的数进行+10操作再进行-30操作,这两步使用多线程执行。A和B线程同时取一个值为100的数C,A对C进行+10操作,B对取出来的值进行-30的操作,如果没有加锁控制,那么A处理的值D不能被B拿到且会被B覆盖。对于加锁这里简单归纳两种:乐观锁和悲观锁,悲观锁会格外注重线程安全,只有等A操作完后才能由B取值;而乐观锁则是通过版本控制的方式来检测是否C被修改了。
未加锁的场景模拟
实体类
- 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接口
- 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
{ -
- }
测试类
- 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());
-
- }
- }
前面知道乐观锁实现需要加上版本号来控制,因此实体类需要进行通过@Version来设置版本号。
实体类
- 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插件配置类
需要在配置类中配置好乐观锁插件方法OptimisticLockerInnerInterceptor()
- 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;
- }
- }
测试类
需要注意的是B修改数据失败后需要重试即可完成任务需求。
- 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());
-
- }
- }
通过条件构造器的几种基本用法使用示例,荔枝对wrapper类的使用有了一个比较直观的理解,同时荔枝觉得更需要注意的是两种插件的使用。接下来的文章中荔枝会对MyBatis-Plus的相关基础知识收尾,同时尝试整合到学习的项目中,跟荔枝一起期待一波吧哈哈哈哈哈~~~
今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~