Redis悲观锁解决高并发抢红包的问题

  • 内容
  • 评论
  • 相关

悲观锁是一种利用数据库内部机制提供的锁的方法,也就是对更新的数据加锁,这样在并发期间一旦有一个事务持有了数据库记录的锁,其他的线程将不能再对数据进行更新了,这就是悲观锁的实现方式。

首先在 RedPacket.xml 中增加一个 id 为 getRedPacketForUpdate 的 SQL,修改为下面的代码:

<!-- 查询红包具体信息 -->
<select id="getRedPacketForUpdate" parameterType="long"
    resultType="com.pojo.RedPacket">
    select id, user_id as userId, amount, send_date as sendDate, total,
        unit_amount as unitAmount, stock, version, note from T_RED_PACKET
        where id =#{id} for update
</select>

注意,在 SQL 中加入的 for update 语句,意味着将持有对数据库记录的行更新锁(因为这里使用主键查询,所以只会对行加锁。如果使用的是非主键查询,要考虑是否对全表加锁的问题,加锁后可能引发其他查询的阻塞),那就意味着在高并发的场景下,当一条事务持有了这个更新锁才能往下操作,其他的线程如果要更新这条记录,都需要等待,这样就不会出现超发现象引发的数据一致性问题了。

再插入一条新记录到数据库里,如下面的代码所示。

insert  into `t_red_packet`(`id`,`user_id`,`amount`,`send_date`,`total`,`unit_amount`,`stock`,`version`,`note`)
values (1,1,'200000.00','2019-07-29 16:35:20',20000,'10',20000,0,'20万元金额,2万个小红包,每个10元');

还是以 20 万元的红包,每个 10 元,共两万个红包为例。插入这条数据后,获取其编号,同时在 RedPacketDao 中加入对应的查询方法。

/**
  * 使用 for update语句加锁
  *
  * @param id红包id
  * @return 红包信息
  */
public RedPacket getRedPacketForUpdate(Long id);

接下来,将 UserRedPacketServiceImpl 代码中的”RedPacket redPacket = redPacketDao.getRedPacket(redPacketId);“的代码修改为以下代码:

Redpacket redpacket = redpacketDao.getRedPacketForUpdate(redpacketId);

做完这些修改后,再次进行测试,便能够得到如图 1 所示的结果。

悲观锁测试结果
图 1  悲观锁测试结果

本文标题:Redis悲观锁解决高并发抢红包的问题

本文地址:https://www.hosteonscn.com/6050.html

评论

0条评论

发表评论

邮箱地址不会被公开。 必填项已用*标注