天天看點

SSM+Redis高并發搶紅包之-悲觀鎖

繼上一次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插入和上次一樣的紅包資料

然後測試

最後在資料庫中進行查詢,如下圖所示

SSM+Redis高并發搶紅包之-悲觀鎖

這裡已經解決了超發的問題,下面看下性能方面

SSM+Redis高并發搶紅包之-悲觀鎖

這裡無限接近1分鐘了,比超發現象那麼多了幾S,這也隻是20000個紅包,而且目前就單獨使用了一個行鎖罷了,如果在後面再加幾個鎖進來,沒有得到鎖的線程不斷的被挂起(這裡挂起也是消耗系統資源的),當某個資源釋放鎖,其他線程又一哄而上,那麼久而久之,系統的性能将不斷下降。是以又有一些大神想出了使用樂觀鎖的機制,關于樂觀鎖,我們下一個部落格 SSM+Redis高并發搶紅包之-樂觀鎖再說