MyBatis-Plus实现分页

一、分页插件实现分页功能

MyBatis Plus自带分页插件,进行配置即可实现分页功能

1.1.添加配置类

在com.augus下创建config包,存放配置类,创建配置类   mybatisPlusInterceptor,内容如下:

package com.augus.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;

@Configuration
@MapperScan("com.augus.mapper")
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;
    }
}

1.2.创建测试代码进行测试

创建测试类 MyBatisPlusPage  内容如下:

package com.augus;

import com.augus.mapper.UserMapper;
import com.augus.pojo.User;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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 MyBatisPlusPage {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testPage(){
        //设置分页
        Page<User> userPage = new Page<>(0, 4);
        //如果查询条件为空,则输入null,如果需要则构建queryWrapper
        userMapper.selectPage(userPage, null);

        //获取分页数据
        List<User> records = userPage.getRecords();
        records.forEach(System.out::println);

        System.out.println("当前的页数:"+userPage.getCurrent());
        System.out.println("每页显示的条数:"+userPage.getSize());
        System.out.println("总记录数:"+userPage.getTotal());
        System.out.println("总页数:"+userPage.getPages());
        System.out.println("是否有上一页:"+userPage.hasPrevious());
        System.out.println("是否有下一页:"+userPage.hasNext());
    }
}

结果如下:

二、xml自定义分页

2.1.在mapper下的UserMapper中定义接口方法

package com.augus.mapper;

import com.augus.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;


public interface UserMapper extends BaseMapper<User> {

    /**
     * 通过年龄查询用户信息进行分页设置
     * @param page mybatis-plus插件提供的分页对象,必须是一个参数
     * @param age 根据年龄分页
     * @return
     */
    Page<User> selectPageVo(@Param("page") Page<?> page, @Param("age") Integer age);
}

2.2在resources包下的创建mapper目录存储mapper映射文件

注意mybatis-plus中存放映射文件的包,默认就叫mapper切记,在下面创建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.augus.mapper.UserMapper">
    <!--
    注意在yml配置文件中就应该需要指定实体类所在的位置
    -->
    <select id="selectPageVo" resultType="User">
        SELECT uid,user_name,age,email FROM t_user WHERE age > #{age}
    </select>
</mapper>

2.3.还是在之前的测试类中进行测试

在之前测试类中添加如下测试方法:

@Test
    public void testPage02(){
        //设置分页
        Page<User> userPage = new Page<>(1, 4);
        //将年龄大于20岁的人员信息进行分页查询
        userMapper.selectPageVo(userPage, 20);

        //获取分页数据
        List<User> records = userPage.getRecords();
        records.forEach(System.out::println);

        System.out.println("当前的页数:"+userPage.getCurrent());
        System.out.println("每页显示的条数:"+userPage.getSize());
        System.out.println("总记录数:"+userPage.getTotal());
        System.out.println("总页数:"+userPage.getPages());
        System.out.println("是否有上一页:"+userPage.hasPrevious());
        System.out.println("是否有下一页:"+userPage.hasNext());
    }

执行后,即可查看获取的信息

三、乐观锁

3.1.场景:

在数据库操作的时,有一条商品信息,有两个人同时去,要调整他的商品价格,那么如果两个同时操作,假设原本价格为40,a用户添加了60,价格就变成了100,但是如果b也在a完成调整价格之前也是获取了40,然后给减去了50,这时候就变成了-10,正常来说有一个人在操作数据,必须要等这个人操作完成后,在基于这个人的结果上操作。而乐观锁就是为了解决这个问题

3.2.模拟修改冲突的场景

3.2.1.创建表:

CREATE TABLE `t_product` (
  `id` bigint(20) NOT NULL COMMENT '主键ID',
  `name` varchar(30) DEFAULT NULL COMMENT '商品名称',
  `price` int(11) DEFAULT '0' COMMENT '价格',
  `VERSION` int(11) DEFAULT '0' COMMENT '乐观锁版本号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.2.2.给表中插入数据:

INSERT INTO t_product (id, name, price) VALUES (1, 'python从入门到放弃', 40);

3.2.3.在com.augus.pojo下创建实体类

package com.augus.pojo;

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

import java.io.Serializable;

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

3.2.4.在com.augus.mapper下创建接口

新建  ProductMapper 内容如下:

package com.augus.mapper;

import com.augus.pojo.Product;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface ProductMapper extends BaseMapper<Product> {
}

3.2.5.创建测试类

package com.augus;

import com.augus.mapper.ProductMapper;
import com.augus.mapper.UserMapper;
import com.augus.pojo.Product;
import com.augus.pojo.User;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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 MyBatisPlusLocker {
    @Autowired
    private ProductMapper productMapper;


    @Test
    public void testConcurrentUpdate(){
        //李铁调整价格
        Product p1 = productMapper.selectById(1);
        System.out.println("李铁获取的价格为:"+p1.getPrice());

        //张鹭调整价格
        Product p2 = productMapper.selectById(1);
        System.out.println("张鹭获取的价格为:"+p2.getPrice());

        //李铁添加价格增加60元,保存数据
        p1.setPrice(p1.getPrice()+60);
        int i1 = productMapper.updateById(p1);
        System.out.println("李铁修改结果:"+i1);


        //张鹭添加价格减少50元,保存数据
        p2.setPrice(p2.getPrice()-50);
        int i2 = productMapper.updateById(p2);
        System.out.println("张鹭修改结果:"+i2);


        //最后BOSS看到的结果
        Product p3 = productMapper.selectById(1);
        System.out.println("BOSS获取的价格为:"+p3.getPrice());
    }
}

执行后结果如下:

3.3.乐观锁解决上述问题

3.3.1.实现原理

给数据库表中添加version字段,取出记录时,获取当前version,更新时,version + 1,如果where语句中的version版本不对,则更新失败

3.3.2.乐观锁配置

修改实体类,给version字段添加 @version注解
package com.augus.pojo;

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

import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Product implements Serializable {
    private Long id;
    private String name;
    private Integer price;
    @Version
    private Integer version;
}
在配置类中添加乐观锁插件配置
package com.augus.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;

@Configuration
@MapperScan("com.augus.mapper")
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        //添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

3.3.3.需要代码,进行测试

在 MyBatisPlusLocker 类中添加如下方法进行测试:

@Test
    public void testConcurrentUpdate02(){
        //李铁调整价格
        Product p1 = productMapper.selectById(1);
        System.out.println("李铁获取的价格为:"+p1.getPrice());

        //张鹭调整价格
        Product p2 = productMapper.selectById(1);
        System.out.println("张鹭获取的价格为:"+p2.getPrice());

        //李铁添加价格增加60元,保存数据
        p1.setPrice(p1.getPrice()+60);
        int i1 = productMapper.updateById(p1);
        System.out.println("李铁修改结果:"+i1);


        //张鹭添加价格减少50元,保存数据
        p2.setPrice(p2.getPrice()-50);
        int i2 = productMapper.updateById(p2);
        System.out.println("张鹭修改结果:"+i2);

        if(i2 == 0){
            //失败重试,获取version并更新
            Product p3 = productMapper.selectById(1);
            //设置价格
            p3.setPrice(p3.getPrice()-50);
            i2 = productMapper.updateById(p3);
        }

        System.out.println("张鹭重试后的结果为:"+i2);

        //最后BOSS看到的结果
        Product p3 = productMapper.selectById(1);
        System.out.println("BOSS获取的价格为:"+p3.getPrice());
    }

测试执行结果如下:

posted @ 2022-12-02 17:51  酒剑仙*  阅读(195)  评论(0)    收藏  举报