java srpint boot 2.2.1 第二部份,锁机制和分页查询 以及统一返回结果格式,

3d引挚技术爱好者 / 2024-04-20 / 原文

第二部份,引起锁机制的原理和解决方案:

 测试环境搭建
第一步先建一个数据库表用于模拟商品购买。

CREATE TABLE product (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    stock INT NOT NULL,
    version INT NOT NULL DEFAULT 0
);

  第二步,新建一个商品类,用于等于mapper 产生方法,如果用插件lombok,   可以在类上面加上@Data 自动生产 自动生成get set 方法

import com.baomidou.mybatisplus.annotation.*;

@TableName("product")
public class Product {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String name;
    private Integer stock;
    private Integer version;
    // 省略Getter和Setter方法
}

第三步,编写 mapper 继承baseMapper, mapper 文件下面新建ProductMapper 接口

public interface ProductMapper extends BaseMapper<Product> {
}

 

最后编写测试用例:

 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);
        productMapper.updateById(p1);
p2.setPrice(p2.getPrice()
-30); productMapper.updateById(p2); //最后的结果 //用户看到的商品价格 Product p3 = productMapper.selectById(1L); System.out.println("最后的结果:" + p3.getPrice()); }

运行结果:明明正确的 业务逻辑  应该是120  结果双方都取出数据来修改,后面修改的覆盖了前面的,

 解决方法一   

  直接锁住这个数据  实际上,在MyBatis中,并不直接使用Java代码来加数据库锁,而是通过编写特定的SQL语句来实现。使用数据库的 ​for update​语句可以进行行级锁定,这通常是在SQL查询中进行,例如: 

SELECT * FROM product WHERE id = 1 FOR UPDATE; 这将锁定id为1的商品记录,直到事务结束才会释放锁。
在MyBatis中可以使用如下方式来执行带有 ​for update​的SQL语句: 
@Select("SELECT * FROM product WHERE id = #{id} FOR UPDATE") Product lockProductForUpdate(Long id); 

注意,​FOR UPDATE​关键字的使用可能因数据库类型而异,你需要根据使用的具体数据库来调整相应的SQL语句。另外,在实际业务中,请留意事务的控制和锁的释放时机,避免出现死锁等问题。并且要手工编写sql 比较麻烦我们后面乐观锁,只需要配置可以直接自动应用,以下是悲观锁的流程示例,属于伪代码

@Test
public void testConcurrentUpdateWithPessimisticLock() {
    Product p = productMapper.selectById(1L);

    // 加悲观锁
    productMapper.lockProductForUpdate(1L);

    // 修改价格
    p.setPrice(p.getPrice() + 50);
    productMapper.updateById(p);

    // 解锁  操作完后自动解锁

    // 获取最终结果
    Product finalProduct = productMapper.selectById(1L);
    System.out.println("Final price: " + finalProduct.getPrice());
}

  解决方二   乐观锁

核心代码思路为以下截图:如果更新失败需要重新业务

 操作流程: