說明:
用redis計數器存取使用者的操作次數,最多3次,但是並發會超過3次,下面的程式碼對嗎?
BoundValueOperations<String, String> operations = redisTemplate.boundValueOps("key1");
String key1 = operations.get();
if (StringUtils.isEmpty(key1)) {
service.do();//这里是业务逻辑操作成功之后,计数器加1
operations.increment(1);
} else {
if (Integer.parseInt(key1) < 2) {
service.do();//这里是业务逻辑操作成功之后,计数器加1
operations.increment(1);
}
}
對於這種計數的業務,應先計數,再做業務。如果業務完成,發現計數器已經大於限定值了,就傻眼了。
我的方案是:
由於是並發導致的數據不一致,可以考慮用 Redis 的
INCR
命令增 1,並獲得最新值(這是一次操作,所以不會造成不一致):如果大於 3,表示已經超過了,結束;
小於等於3,再執行業務(可能還要考慮業務執行失敗回滾計數器)。
透過java客戶端實現上述功能有一定的缺陷,在高並發的情況下,資料可能有不一致的情況;建議使用lua腳本封裝整個邏輯,保證操作的原子性;可以透過SCRIPT LOAD的方式將腳本緩存到伺服器,透過sha1校驗值+參數(Key,ARG)來執行,減輕網路傳輸;
給你一個範例:
1.功能需求:key如果不存在,則set並返回false,並設定超時時間和count=1;達到超時時間或達到指定的count數,返回false 並重新設定超時時間和count=1;如果沒有達到超時時間& 沒有達到指定的count,回傳true,並且incr count
redis.lua腳本如下:
java程式碼如下: