一、分页插件实现分页功能
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());
}
测试执行结果如下: