插件
分页插件
- 编写配置类
@Configuration
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
- 测试
@SpringBootTest
public class MyBatisPlusPluginsTest {
@Autowired
private UserMapper userMapper;
@Test
public void testPage(){
Page<User> page = new Page<>(2, 3);
userMapper.selectPage(page, null);
System.out.println(page.getRecords()); // 获取当前页数据
System.out.println(page.getPages()); // 总页数
System.out.println(page.getTotal()); // 总记录数
System.out.println(page.hasNext()); // 是否有上一条
System.out.println(page.hasPrevious()); // 是否有下一条
}
}
- 自定义xml
# mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
/**
* 通过年龄查询用户信息并分页
* @param page MyBatis-Plus所提供的分页对象,必须位于第一个参数的位置
* @param age
* @return
*/
Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
}
# xml
<select id="selectPageVo" resultType="User">
select uid,user_name,age,email from t_user where age > #{age}
</select>
# yml
mybatis-plus:
# 配置类型别名所对应的包
type-aliases-package: com.atguigu.mybatisplus.pojo
# 测试
@Test
public void testPageVo(){
Page<User> page = new Page<>(1, 3);
userMapper.selectPageVo(page, 20);
System.out.println(page.getRecords());
System.out.println(page.getPages());
System.out.println(page.getTotal());
System.out.println(page.hasNext());
System.out.println(page.hasPrevious());
}
乐观锁插件
-
当2个事务同时操作1条数据时,会产生冲突,这时需要使用锁
-
模拟冲突
# 创建表
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);
# 编写实体类
@Data
public class Product {
private Long id;
private String name;
private Integer price;
private Integer version;
}
# mapper层
public interface ProductMapper extends BaseMapper<Product> {
}
# 测试,最终查询结果预期是120,实际是70
@Test
public void testConcurrentUpdate() {
//1、小李
Product p1 = productMapper.selectById(1L);
System.out.println("小李取出的价格:" + p1.getPrice());
//2、小王
Product p2 = productMapper.selectById(1L);
System.out.println("小王取出的价格:" + p2.getPrice());
//3、小李将价格加了50元,存入了数据库
p1.setPrice(p1.getPrice() + 50);
int result1 = productMapper.updateById(p1);
System.out.println("小李修改结果:" + result1);
//4、小王将商品减了30元,存入了数据库
p2.setPrice(p2.getPrice() - 30);
int result2 = productMapper.updateById(p2);
System.out.println("小王修改结果:" + result2);
//最后的结果
Product p3 = productMapper.selectById(1L);
//价格覆盖,最后的结果:70
System.out.println("最后的结果:" + p3.getPrice());
}
- 乐观锁实现流程
数据库中添加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
- 配置乐观锁插件
@Configuration
//扫描mapper接口所在的包
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
- 实体类添加乐观锁注解
@Data
public class Product {
private Long id;
private String name;
private Integer price;
@Version //标识乐观锁版本号字段,数据库中version为0
private Integer version;
}
- 测试,第1次修改成功,由于乐观锁,第2次版本不正确,修改失败;所以最终查询结果是150
@Test
public void testProduct01(){
//小李查询商品价格
Product productLi = productMapper.selectById(1);
System.out.println("小李查询的商品价格:"+productLi.getPrice());
//小王查询商品价格
Product productWang = productMapper.selectById(1);
System.out.println("小王查询的商品价格:"+productWang.getPrice());
//小李将商品价格+50
productLi.setPrice(productLi.getPrice()+50);
productMapper.updateById(productLi);
//小王将商品价格-30
productWang.setPrice(productWang.getPrice()-30);
int result = productMapper.updateById(productWang);
//老板查询商品价格
Product productLaoban = productMapper.selectById(1);
System.out.println("老板查询的商品价格:"+productLaoban.getPrice());
}
- 优化,第2次修改失败后,重试,最终查询为预期结果120
@Test
public void testProduct01(){
//小李查询商品价格
Product productLi = productMapper.selectById(1);
System.out.println("小李查询的商品价格:"+productLi.getPrice());
//小王查询商品价格
Product productWang = productMapper.selectById(1);
System.out.println("小王查询的商品价格:"+productWang.getPrice());
//小李将商品价格+50
productLi.setPrice(productLi.getPrice()+50);
productMapper.updateById(productLi);
//小王将商品价格-30
productWang.setPrice(productWang.getPrice()-30);
int result = productMapper.updateById(productWang);
if(result == 0){
//操作失败,重试
Product productNew = productMapper.selectById(1);
productNew.setPrice(productNew.getPrice()-30);
productMapper.updateById(productNew);
}
//老板查询商品价格
Product productLaoban = productMapper.selectById(1);
System.out.println("老板查询的商品价格:"+productLaoban.getPrice());
}