SSM+Redis高并发抢红包之-悲观锁

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/toward_south/article/details/89785831

继上一次SSM+Redis高并发抢红包之-超发现象的问题解决,这里我们使用悲观锁来解决

首先我们需要了解什么是悲观锁(也叫独占锁)

悲观锁是一种利用数据库内部机制提供的锁的方法,也就是对更新的数据加锁

我这里使用的是mysql, 存储引擎是InnoDB 这个是支持事务和行锁的。而这里我们使用的就是行锁

关于mysql相关锁及其原理,这里可以看下这篇博客,我觉得很nice   MySQL学习之——锁(行锁、表锁、页锁、乐观锁、悲观锁等)

在这里悲观锁的实现方式,就是在并发期间一旦有一个事务持有数据库记录的锁,那么其他的线程将不能再对数据进行更新。

在这次实验中,我们只需要添加少量代码,代码如下:

1.在RedPacketDao 接口类中添加

/*
	 * 获取红包信息,使用悲观锁
	 * @param id 红包id
	 * @return 红包具体信息
	 */
	public RedPacket getRedPacketForUpdate(Long id);

2.在RedPacket.xml中添加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语句

如果在sql语句中加了for update ,那么就意味着将持有对数据库记录的行更新锁,因为这里我们的id 设置为primary key ,而当前查询为主键查询,那么这里就只会是对行加锁。如果使用非主键查询,那么就需要考虑是否对全表加锁的问题。

然后在UserRedPacketServiceImpl 接口类里 重新添加获取红包信息的接口,如下面代码中注释for update那行代码

public int grapRedPacket(Long redPacketId, Long userId) {
		//获取红包信息
		//RedPacket redPacket = redPacketDao.getRedPacket(redPacketId);
		//获取红包信息,for update
		RedPacket redPacket = redPacketDao.getRedPacketForUpdate(redPacketId);
		//当前小红包库存大于0
		if(redPacket.getStock() > 0) {
			redPacketDao.decreaseRedPacket(redPacketId);
			//生成抢红包信息
			UserRedPacket userRedPacket = new UserRedPacket();
			userRedPacket.setRedPacketId(redPacketId);
			userRedPacket.setRedPacketId(redPacketId);
			userRedPacket.setUserId(userId);
			userRedPacket.setAmount(redPacket.getUnitAmount());
			userRedPacket.setNote("抢红包 "+ redPacketId);
			//插入抢红包信息
			int result = userRedPacketDao.grapRedPacket(userRedPacket);
			return result;
		}
		return FAILED;
	}

最后我们再向t_red_packet插入和上次一样的红包数据

然后测试

最后在数据库中进行查询,如下图所示

这里已经解决了超发的问题,下面看下性能方面

这里无限接近1分钟了,比超发现象那么多了几S,这也只是20000个红包,而且当前就单独使用了一个行锁罢了,如果在后面再加几个锁进来,没有得到锁的线程不断的被挂起(这里挂起也是消耗系统资源的),当某个资源释放锁,其他线程又一哄而上,那么久而久之,系统的性能将不断下降。所以又有一些大神想出了使用乐观锁的机制,关于乐观锁,我们下一个博客SSM+Redis高并发抢红包之-乐观锁 再说

猜你喜欢

转载自blog.csdn.net/toward_south/article/details/89785831