MySQL乐观锁与悲观锁-第二弹

前言

数据库中的乐观锁与悲观锁,这是我们在处理并发访问数据库时经常会遇到的问题。通过了解这两种锁的工作原理,我们可以更好地处理并发访问,确保数据的一致性和完整性。

乐观锁

简介

首先,让我们来了解一下什么是乐观锁。**乐观锁的核心思想是假设在大多数情况下,并发访问的数据不会产生冲突。**它采用了一种轻量级的方式,不会阻塞其他的并发操作,而是在进行数据更新时,先获取数据的版本号或者时间戳,然后在更新数据之前再次检查版本号或时间戳是否发生变化。如果变化了,就意味着有其他并发操作修改了数据,那么当前操作就会失败,需要重新尝试。这种方式避免了长时间的锁等待,提高了并发性能。

下面就让我们通过一个具体的例子来说明乐观锁的应用。假设我们有一个在线商城,用户可以同时下单购买商品。在数据库中,每个订单都会有一个版本号字段。当用户下单时,系统会查询当前商品的库存量和价格,并生成一个订单,同时将库存量减少。在这个过程中,我们可以使用乐观锁来避免多个用户同时购买同一件商品的问题。

代码实现

乐观锁的具体实现,我们可以使用mybatis-plus的插件实现,具体步骤如下:

step1:数据表中加version字段,默认值设置为1;
step2:实体类中加version属性,同时属性上面加@Version注解;
step3:添加乐观锁插件。


 @Bean
 public MybatisPlusInterceptor interceptor(){
     MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
     //添加分页插件
     interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
     //添加乐观锁插件
     interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
     return  interceptor;
 }

业务代码

package com.qf.service;
import com.qf.entity.TbGoods;
import com.qf.entity.TbOrder;
import com.qf.mapper.TbGoodsMapper;
import com.qf.mapper.TbOrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.UUID;

@Service
public class OrderService {
    @Autowired
    private TbGoodsMapper goodsMapper;
    @Autowired
    private TbOrderMapper orderMapper;

    @Transactional
    public void buy(String goodsId){
        //1:查询商品信息 获取乐观锁
        TbGoods tbGoods = goodsMapper.selectById(goodsId);
        if (tbGoods == null) {
            return;
        }

        //2:判断库存
        if(tbGoods.getGoodsStock1() <= 1){
            return;
        }

        //3:下单
        TbOrder tbOrder = new TbOrder();
        tbOrder.setOrderId(UUID.randomUUID().toString());
        tbOrder.setGoodsId(Integer.parseInt(goodsId));
        tbOrder.setOrderAmount(tbGoods.getGoodsPrice());
        orderMapper.insert(tbOrder);

        //4:修改库存
        tbGoods.setGoodsStock1(tbGoods.getGoodsStock1() - 1);
        int i = goodsMapper.updateById(tbGoods);
        if(i == 0){//其他业务影响了数据
            throw  new RuntimeException("数据被人动过!!!");
        }
    }
}

悲观锁

简介

接下来,我们再来了解一下什么是悲观锁。悲观锁的实现思想与乐观锁相反,它假设在并发访问中,数据会频繁发生冲突。因此,在操作数据之前,悲观锁会对数据进行加锁,确保其他并发操作无法同时访问该数据。

例如,小明和小红同时购买了同一件商品,系统会生成两个订单。在执行减少库存的操作之前,系统会对该商品的库存进行加锁。这意味着只有一个用户能够成功地执行减少库存的操作,而另一个用户必须等待第一个用户完成操作并释放锁后才能执行。

通过使用悲观锁,我们可以有效避免多个用户同时购买同一件商品导致的库存冲突问题。悲观锁确保了数据的一致性,但也带来了一些性能上的损耗,因为其他用户必须等待锁的释放才能继续操作。

代码实现

@Select("select * from tb_goods where goods_id = #{goodsId} for update")
public TbGoods lock(String goodsId);

业务代码

package com.qf.service;
import com.qf.entity.TbGoods;
import com.qf.entity.TbOrder;
import com.qf.mapper.TbGoodsMapper;
import com.qf.mapper.TbOrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.UUID;

@Service
public class OrderService {
    @Autowired
    private TbGoodsMapper goodsMapper;
    @Autowired
    private TbOrderMapper orderMapper;

    @Transactional
    public void buy(String goodsId){
        //获取数据库悲观锁(行锁)
        goodsMapper.lock(goodsId);

        //1:查询商品信息
        TbGoods tbGoods = goodsMapper.selectById(goodsId);
        if (tbGoods == null) {
            return;
        }

        //2:判断库存
        if(tbGoods.getGoodsStock1() <= 1){
            return;
        }

        //3:下单
        TbOrder tbOrder = new TbOrder();
        tbOrder.setOrderId(UUID.randomUUID().toString());
        tbOrder.setGoodsId(Integer.parseInt(goodsId));
        tbOrder.setOrderAmount(tbGoods.getGoodsPrice());
        orderMapper.insert(tbOrder);

        //4:修改库存
        tbGoods.setGoodsStock1(tbGoods.getGoodsStock1() - 1);
        goodsMapper.updateById(tbGoods);
    }
}

总结

总的来说,乐观锁和悲观锁都是处理数据库并发访问的重要工具,它们各自具有不同的适用场景和优势。在实际应用中,我们需要综合考虑业务需求、数据一致性要求以及并发性能,选择合适的锁策略来保证系统的稳定性和性能表现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yinying293

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值