一、前言
什麼是鎖,為什麼需要鎖,拿一個簡單例子,新增賬號,一般需要三步:
- 根據賬号查詢資料庫,擷取查詢結果
- 判斷結果賬号是否為空
- 如果為空則進行注冊,不為空傳回該賬戶已被注冊。
如果兩個人同時用同一個賬号注冊,第一個人已經走到了第三步,已經判斷了資料庫該賬号沒有被注冊,正準備注冊但是還沒有注冊,此時第二個人判斷資料庫該賬戶沒有被注冊,也走到了第三步。然後兩個人用同一個賬号都注冊了一次,資料庫産生了兩條相同的記錄。
涉及到搶購資源的時候就會涉及到鎖,單體應用中簡單粗暴的方式就是用
synchronized
,或者用樂觀鎖,在資料庫上加上一個類似
version
的判斷。
但是在微服務中,一個服務會部署多個執行個體,而且資料庫有可能也是分庫分表的,是以就需要借助第三方中間件來解決分布式鎖。
Redis
利用它資料結構的特性可以做分布式鎖,但是需要自己寫腳本,
Redisson
是基于
Redis
封裝的,簡單好用,不需要自己再寫腳本。
二、Maven依賴
pom.xml
添加如下依賴
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
三、application.properties
配置檔案加上redis的配置資訊
# redis 相關
spring.redis.host=localhost
spring.redis.port=6379
四、使用Redisson
這裡模拟客戶下單:先減商品庫存、然後建立訂單
package com.llh.consumer.service.impl;
import com.llh.consumer.service.ConsumerService;
import com.llh.order.api.feign.OrderApi;
import com.llh.product.api.feign.ProductApi;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author 小虎哥的技術部落格
*/
@Service
public class ConsumerServiceImpl implements ConsumerService {
@Resource
private RedissonClient redissonClient;
@Resource
private ProductApi productApi;
@Resource
private OrderApi orderApi;
@Override
public Boolean buy(Long productId, Integer number) {
RLock lock = redissonClient.getLock("lock_key");
// 加鎖
lock.lock();
// 先減商品庫存
boolean decreaseResult = productApi.decrease(productId, number);
if (decreaseResult) {
// 商品庫存減成功後 建立訂單
boolean createResult = orderApi.create(productId, number);
// 解鎖
lock.unlock();
return createResult;
}
return false;
}
}
五、測試
資料庫商品數量為100,每次購買一個。用Jmeter測試:10個線程同時請求。
沒有加鎖,共産生了333個訂單
加鎖,100個商品就100個訂單,正常。
測試的時候可以在
lock.unlock()
那裡加個斷點,然後檢視redis資料庫,可以看到資料庫裡面有
lock_key
的key,然後
lock.unlock()
結束後這個key就自動删除了。
六、結語
分布式鎖非常重要,生産環境中肯定會需要。你想如果倉庫裡面隻有100瓶茅台,卻賣給了333個人,一旦發生這種事故,開發人員和測試人員就該領便當咯。
這裡隻是最簡單的應用,有條件的同學可以去了解一下假如某個線程因為不确定的錯誤異常導緻沒有釋放鎖,導緻後面的請求全部進不來怎麼辦?
源碼位址:https://github.com/tigerleeli/xiaohuge-blog/tree/master/spring-cloud-alibaba-redisson
同步微信公衆号:小虎哥的技術部落格