MyBatis-Plus的插件

一、分页插件

1.自带的

启动类

在启动类里配置分页相关内容

java 复制代码
package com.qcby;

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.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@MapperScan("com.qcby.mybatisPlus.mapper")
public class MybatisPlusApplication {
    public static void main(String[] args) {
        //springboot应用启动起来
        SpringApplication.run(MybatisPlusApplication.class, args);
    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new
                PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

测试类

java 复制代码
package com.qcby.mybatisPlus;

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

import java.util.List;

@SpringBootTest
public class PageTest {

    @Autowired
    private UserMapper userMapper;

    /*
    * 自带的
    * */
    @Test
    public void testPage(){
        //设置分页参数
        Page<User> page = new Page<>(1, 5);//当前页,每页展示数量
        userMapper.selectPage(page, null);
        //获取分页数据
        List<User> list = page.getRecords();
        list.forEach(System.out::println);
        System.out.println("当前页:"+page.getCurrent());
        System.out.println("每页显示的条数:"+page.getSize());
        System.out.println("总记录数:"+page.getTotal());
        System.out.println("总页数:"+page.getPages());
        System.out.println("是否有上一页:"+page.hasPrevious());
        System.out.println("是否有下一页:"+page.hasNext());
        /*
        * SELECT COUNT(*) AS total FROM t_user WHERE is_deleted = 0 total=18
        * SELECT uid AS id,name,age,email,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?
        * 当前页:1
        * 每页显示的条数:5
        * 总记录数:18
        * 总页数:4
        * 是否有上一页:false
        * 是否有下一页:true
        * */
    }
}

测试结果

复制代码
User(uid=1, name=qcby, age=18, email=qcby@qq.com, isDeleted=0)
User(uid=2, name=张三, age=20, email=test2@baomidou.com, isDeleted=0)
User(uid=3, name=Tom, age=28, email=test3@baomidou.com, isDeleted=0)
User(uid=4, name=Sandy, age=21, email=test4@baomidou.com, isDeleted=0)
User(uid=5, name=Billie, age=24, email=test5@baomidou.com, isDeleted=0)
当前页:1
每页显示的条数:5
总记录数:18
总页数:4
是否有上一页:false
是否有下一页:true

2.自定义分页

UserMapper接口

UserMapper中定义接口方法

java 复制代码
package com.qcby.mybatisPlus.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qcby.mybatisPlus.model.User;
import org.apache.ibatis.annotations.Param;

/*
* mybatisPlus的持久层接口
* 继承BaseMapper<T>---框架提供好的
* 向上提取的思想
* */
public interface UserMapper extends BaseMapper<User> {
    /**
     * 根据年龄查询用户列表,分页显示
     * @param page 分页对象 ,xml中可以从里面进行取值 ,传递参数 Page 即自动分页 ,必须放在第一位
     * @param age 年龄
     * @return */
    Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
}

UserMapper.xml

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.qcby.mybatisPlus.mapper.UserMapper"> <!--对谁进行操作就写谁-->

    <!--SQL片段,记录基础字段-->
    <sql id="BaseColumns">uid,name,age,email</sql>

    <!--IPage<User> selectPageVo(Page<User> page, Integer age);-->
    <select id="selectPageVo" resultType="user">
        SELECT <include refid="BaseColumns"></include> FROM t_user WHERE age > # {age}
    </select>
</mapper>

application.yml配置文件

在配置文件里配置xml文件所在位置

yaml 复制代码
# 配置MyBatis日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 配置mybatis_plus操作表的默认前缀
      table-prefix: t_
      #id-type: auto #配置MyBatis-Plus的主键策略
  mapper-locations: classpath:mapper/*.xml #对应mapper映射文件xml文件所在位置
  type-aliases-package: com.qcby.mybatisPlus.model #对应实体类所在位置

测试类

java 复制代码
/*
* 自定义的
* */
@Test
public void testSelectPageVo(){
    //设置分页参数
    Page<User> page=new Page<>(1,5);//当前页,每页展示数量
    userMapper.selectPageVo(page,20);//自己写的方法
    //获取分页数据
    List<User> list = page.getRecords();
    list.forEach(System.out::println);
    System.out.println("当前页:"+page.getCurrent());
    System.out.println("每页显示的条数:"+page.getSize());
    System.out.println("总记录数:"+page.getTotal());
    System.out.println("总页数:"+page.getPages());
    System.out.println("是否有上一页:"+page.hasPrevious());
    System.out.println("是否有下一页:"+page.hasNext());
    /*
    * SELECT COUNT(*) AS total FROM t_user WHERE age > ?(20)  total=9
    * SELECT uid,name,age,email FROM t_user WHERE age > ? LIMIT ?
    * 当前页:1
    * 每页显示的条数:5
    * 总记录数:9
    * 总页数:2
    * 是否有上一页:false
    * 是否有下一页:true
    * */
}

测试结果

复制代码
User(uid=3, name=Tom, age=28, email=test3@baomidou.com, isDeleted=null)
User(uid=4, name=Sandy, age=21, email=test4@baomidou.com, isDeleted=null)
User(uid=5, name=Billie, age=24, email=test5@baomidou.com, isDeleted=null)
User(uid=10, name=szy0, age=28, email=user111@qcby.com, isDeleted=null)
User(uid=11, name=szy1, age=28, email=user111@qcby.com, isDeleted=null)
当前页:1
每页显示的条数:5
总记录数:9
总页数:2
是否有上一页:false
是否有下一页:true

二、乐观锁

场景

一件商品,成本价是80元,售价是100元。老板先通知小李,把商品价格增加50元。但是小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王把商品价格降低30元。

此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据 库;小王将商品减了30元,并将100-30=70元存入了数据库。那么,如果没有锁,小李的操作就完全被小王的覆盖了。

乐观锁与悲观锁

上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过 了,则重新取出的被修改后的价格, 150元,这样他会将120元存入数据库。

如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证 最终的价格是120元。

模拟修改冲突

数据库中增加商品表

sql 复制代码
CREATE TABLE t_product
(
    id BIGINT(20) NOT NULL COMMENT '主键ID',
    NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称 ',
    price INT(11) DEFAULT 0 COMMENT '价格 ',
    VERSION INT(11) DEFAULT 0 COMMENT '乐观锁版本号 ',
    PRIMARY KEY (id)
);

添加数据

sql 复制代码
INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人笔记本 ', 100);

添加实体类Product

因为在配置文件配置了mybatis_plus操作表的默认前缀,所以这里不用加@TableName注解

java 复制代码
package com.qcby.mybatisPlus.model;

import lombok.Data;

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

添加Mapper接口

java 复制代码
package com.qcby.mybatisPlus.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qcby.mybatisPlus.model.Product;

public interface ProductMapper extends BaseMapper<Product> {
}

测试类

java 复制代码
/*
* 模拟修改冲突
* */
@Test
public void testConcurrentUpdate(){
    //1.小李
    Product p1=productMapper.selectById(1);//SELECT id,name,price,version FROM t_product WHERE id=?
    System.out.println("小李取出的价格:"+p1.getPrice());//小李取出的价格:100

    //2.小王
    Product p2=productMapper.selectById(1);//SELECT id,name,price,version FROM t_product WHERE id=?
    System.out.println("小王取出的价格:"+p2.getPrice());//小王取出的价格:100

    //3.小李将价格加了50元
    p1.setPrice(p1.getPrice()+50);
    int result1=productMapper.updateById(p1);//UPDATE t_product SET name=?, price=?, version=? WHERE id=?
    System.out.println("小李修改结果:"+result1);//小李修改结果:1

    //4.小王将价格减了30元
    p2.setPrice(p2.getPrice()-30);
    int result2=productMapper.updateById(p2);//UPDATE t_product SET name=?, price=?, version=? WHERE id=?
    System.out.println("小王修改结果:"+result2);//小王修改结果:1

    //5.最后的结果
    Product p3=productMapper.selectById(1);//SELECT id,name,price,version FROM t_product WHERE id=?
    //价格覆盖,最后的结果是70
    System.out.println("最后的结果:"+p3.getPrice());//最后的结果:70
}

乐观锁实现流程

数据库中添加version字段,取出记录时,获取当前的version:SELECT id,name,price,version FROM product WHERE id=1

更新时,version+1,如果where语句中的version版本不对,则更新失败:

UPDATE product SET price=price+50, version=version + 1 WHERE id=1 AND version=1

mybatis_plus实现乐观锁

修改实体类

java 复制代码
package com.qcby.mybatisPlus.model;

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;
}

添加乐观锁插件配置---启动类

java 复制代码
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    //添加分页插件
    interceptor.addInnerInterceptor(new
            PaginationInnerInterceptor(DbType.MYSQL));
    //添加乐观锁插件
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;
}

测试类优化流程

java 复制代码
/*
* 优化流程
* */
@Test
public void testConcurrentUpdate2(){
    //1.小李取数据
    Product p1=productMapper.selectById(1);
    /*
    * SELECT id,name,price,version FROM t_product WHERE id=?
    * Parameters: 1(Integer)
    * 1, 外星人笔记本 , 100, 0
    * */

    //2.小王取数据
    Product p2=productMapper.selectById(1);
    /*
    * SELECT id,name,price,version FROM t_product WHERE id=?
    * Parameters: 1(Integer)
    * 1, 外星人笔记本 , 100, 0
    * */

    //3.小李修改+50
    p1.setPrice(p1.getPrice()+50);
    int result1=productMapper.updateById(p1);
    System.out.println("小李修改结果:"+result1);
    /*
    * UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
    * Parameters: 外星人笔记本 (String), 150(Integer), 1(Integer), 1(Long), 0(Integer)
    * 小李修改结果:1
    * */

    //4.小王修改-30
    p2.setPrice(p2.getPrice()-30);
    int result2=productMapper.updateById(p2);
    System.out.println("小王修改结果:"+result2);
    if (result2==0){
        //失败,重试
        p2=productMapper.selectById(1);
        p2.setPrice(p2.getPrice()-30);
        result2=productMapper.updateById(p2);
    }
    System.out.println("小王修改重试结果:"+result2);
    /*
    * UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
    * 外星人笔记本 (String), 70(Integer), 1(Integer), 1(Long), 0(Integer)
    * 小王修改结果:0
    * 失败重试:---------------------------------------------------------------
    * SELECT id,name,price,version FROM t_product WHERE id=?
    * Parameters: 1(Integer)
    * 1, 外星人笔记本 , 150, 1
    * UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
    * 外星人笔记本 (String), 120(Integer), 2(Integer), 1(Long), 1(Integer)
    * 小王修改重试结果:1
    * */

    //5.查看结果
    Product p3=productMapper.selectById(1);
    System.out.println("最后的结果:"+p3.getPrice());
    /*
    * SELECT id,name,price,version FROM t_product WHERE id=?
    * Parameters: 1(Integer)
    * 1, 外星人笔记本 , 120, 2
    * 最后的结果:120
    * */
}
相关推荐
缺点内向3 小时前
Java:创建、读取或更新 Excel 文档
java·excel
带刺的坐椅3 小时前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看5 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程5 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t5 小时前
ZIP工具类
java·zip
lang201509285 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
pengzhuofan6 小时前
第10章 Maven
java·maven
百锦再7 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说7 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多7 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring