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

MybatisPlus(SpringBoot版)学习第六讲:插件(分页插件乐观锁)

目录

1.分页插件

1.1 添加配置类

1.2 测试

2.xml自定义分页

2.1 UserMapper中定义接口方法

2.2 UserMapper.xml中编写SQL

2.3 测试

3. 乐观锁

 3.1 场景

3.2 乐观锁与悲观锁

3.3 模拟修改冲突

1. 数据库增加商品表

2. 添加数据

 3. 添加实体

4. 添加mapper

5. 测试

 3.4 乐观锁实现流程

3.5 乐观锁实现流程

1. 修改实体类

 2. 添加乐观锁插件配置

 3. 测试修改冲突

 4. 优化流程


1.分页插件

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

1.1 添加配置类

@Configuration
@MapperScan("com.qcby.mybatisplus.mapper")//可以将主类中的注解移到此处
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new
                PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

1.2 测试

@Test
   public void testPage1(){
//设置分页参数
      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());
   }


2.xml自定义分页

2.1 UserMapper中定义接口方法

@Repository
public interface UserMapper extends BaseMapper<User> {
    /**
     * 根据年龄查询用户列表,分页显示
     * @param page 分页对象 ,xml中可以从里面进行取值 ,传递参数 Page 即自动分页 ,必须放在第一位
     * @param age 年龄
     * @return */
    IPage<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
}

注意!!

        分页的插件不要删掉,他是分页功能的前提。

2.2 UserMapper.xml中编写SQL

<?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,username,age,email</sql>

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

配置映射:

mybatis-plus:
  configuration:
    # 配置MyBatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 配置MyBatis-Plus操作表的默认前缀
      table-prefix: t_
      # 配置MyBatis-Plus的主键策略
      id-type: auto
  mapper-locations: classpath:mapper/*.xml

2.3 测试

@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());
   }


3. 乐观锁

 3.1 场景

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

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

        现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1 万多。

3.2 乐观锁与悲观锁

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

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

3.3 模拟修改冲突

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

2. 添加数据

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

 

 3. 添加实体

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

4. 添加mapper


@Repository
public interface ProductMapper extends BaseMapper<Product> {
}

5. 测试

@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());
	}

 

 

 

显然,最后的结果是70. 

 3.4 乐观锁实现流程

 数据库中添加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

3.5 乐观锁实现流程

1. 修改实体类

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

 2. 添加乐观锁插件配置

@Configuration
@MapperScan("com.qcby.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;
    }
}

 3. 测试修改冲突

 小李查询商品信息:

SELECT id,name,price,version FROM t_product WHERE id=?

 小王查询商品信息:

SELECT id,name,price,version FROM t_product WHERE id=?

 

 小李修改商品价格,自动将version+1

UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
Parameters: 外星人笔记本(String), 150(Integer), 1(Integer), 1(Long), 0(Integer)

 

 小王修改商品价格,此时version已更新,条件不成立,修改失败

UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
Parameters: 外星人笔记本(String), 70(Integer), 1(Integer), 1(Long), 0(Integer)

 

 最终,小王修改失败,查询价格:  150

 

SELECT id,name,price,version FROM t_product WHERE id=?

 

 4. 优化流程

@Test
	public void testConcurrentVersionUpdate() {

		//小李取数据
		Product p1 = productMapper.selectById(1L);

		//小王取数据
		Product p2 = productMapper.selectById(1L);

		//小李修改 + 50
		p1.setPrice(p1.getPrice() + 50);
		int result1 = productMapper.updateById(p1);
		System.out.println("小李修改的结果:" + result1);

		//小王修改 - 30
		p2.setPrice(p2.getPrice() - 30);
		int result2 = productMapper.updateById(p2);
		System.out.println("小王修改的结果:" + result2);
		if(result2 == 0){
			//失败重试,重新获取version并更新
			p2 = productMapper.selectById(1L);
			p2.setPrice(p2.getPrice() - 30);
			result2 = productMapper.updateById(p2);
		}
		System.out.println("小王修改重试的结果:" + result2);

		//老板看价格
		Product p3 = productMapper.selectById(1L);
		System.out.println("老板看价格:" + p3.getPrice());
	}

相关文章:

  • dom0-kernel: /thermal-zones/soc_max/cooling-maps/map0: could not find phandle 2
  • (C语言)指针运算 习题练习1.2(压轴难题)
  • kali利用msf渗透Windows电脑测试
  • 《Keras 3 :AI 使用图神经网络和 LSTM 进行交通流量预测》
  • 数据结构之多项式相加的链表实现
  • PHP文件的导出和导入
  • 蓝桥杯省模拟赛 01串个数
  • 攻破tensorflow,勇创最佳agent(1)---学习率learning_rate问题
  • 【云服务器】在 Linux(Ubuntu / CentOS 7)上快速搭建我的世界 Minecraft 服务器,并实现远程联机,详细教程
  • 笔记:代码随想录算法训练营day62:108.冗余连接、109.冗余连接II
  • MybatisPlus(SpringBoot版)学习第四讲:常用注解
  • PHP MySQL 预处理语句
  • leetcode240.搜索二维矩阵||
  • udp通信(一)
  • VUE3+TypeScript项目,使用html2Canvas+jspdf生成PDF并实现--分页--页眉--页尾
  • 使用LLaMAFactory微调Qwen大模型
  • QT计算器开发
  • kubesphere 终端shell连不上的问题
  • FPGA Verilog/VHDl 中的锁存latch
  • leetcoed0044. 通配符匹配 hard
  • 博柏利上财年营收下降17%,计划裁员1700人助推股价涨超18%
  • 汕头违建豪宅“英之园”将强拆,当地:将根据公告期内具体情况采取下一步措施
  • 安徽省委副秘书长、省委政研室主任余三元调任省社科院院长
  • 周启鸣加盟同济大学,曾任香港浸会大学深圳研究院院长
  • 上海能源科技发展有限公司原董事长李海瑜一审获刑13年
  • 库尔德工人党决定自行解散