当前位置: 首页 > article >正文

MyBatis-Plus的插件

一、分页插件

1.自带的

启动类

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

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

测试类

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中定义接口方法

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 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文件所在位置

# 配置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 #对应实体类所在位置

测试类

/*
* 自定义的
* */
@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元。

模拟修改冲突

数据库中增加商品表

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

添加数据

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

添加实体类Product

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

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接口

package com.qcby.mybatisPlus.mapper;

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

public interface ProductMapper extends BaseMapper<Product> {
}

测试类

/*
* 模拟修改冲突
* */
@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实现乐观锁

修改实体类

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

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

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

测试类优化流程

/*
* 优化流程
* */
@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
    * */
}

http://www.kler.cn/a/516482.html

相关文章:

  • 【C++】string类模拟实现
  • 微调Qwen2:7B模型,加入未知信息语料
  • SpringBoot使用MockMVC通过http请求controller控制器调用测试
  • 编程界“华山论剑”:PHP与Go,谁主沉浮?
  • DeepSeek-R1:性能对标 OpenAI,开源助力 AI 生态发展
  • NodeJs如何做API接口单元测试? --【elpis全栈项目】
  • 如何查找pom文件未使用的依赖
  • 窥探QCC518x-308x系列与手机之间的蓝牙HCI记录与分析 - 耳机篇
  • RabbitMQ2-简单案例
  • JVM深入学习(一)
  • 尚硅谷大数据数仓项目superset db upgrade报错解决(2025.1.23解决)
  • 云原生时代,如何构建高效分布式监控系统
  • OSCP - Proving Grounds - Quackerjack
  • C语言小任务——寻找水仙花数
  • springboot基于微信小程序的商城系统
  • CPU中断机制
  • Ubuntu 24.04 LTS 通过 docker desktop 安装 seafile 搭建个人网盘
  • 分词器的词表大小以及如果分词器的词表比模型的词表大,那么模型的嵌入矩阵需要被调整以适应新的词表大小。
  • MySQL命令及用法(精华版)
  • 接口 V2 完善:基于责任链模式、Canal 监听 Binlog 实现数据库、缓存的库存最终一致性
  • 2024 行远自迩,笃行不怠
  • Geek Uninstaller,绿色免安装轻量的应用卸载工具!
  • 微软预测 AI 2025,AI Agents 重塑工作形式
  • 细节增强卷积DEConv详解及代码复现
  • 基于java的客户信息管理系统
  • Kafka面试题----Kafka中的Producer、Broker、Consumer以及Topic的概念