第二部份,引起锁机制的原理和解决方案:
测试环境搭建
第一步先建一个数据库表用于模拟商品购买。
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()); }
解决方二 乐观锁
核心代码思路为以下截图:如果更新失败需要重新业务
操作流程:
标签:Product,java,boot,1L,srpint,productMapper,selectById,getPrice,id From: https://www.cnblogs.com/ZzwWan/p/18147157