分佈式鎖,當前代碼中, 會循環嘗試執行獲取鎖對象,每一秒一次。
如果鎖沒有釋放而退出,會導致死鎖的現象, 在看官的場合中,可以對while做調整 退出循環。 例如嘗試5次失敗則退出。
import com.kakacl.product_service.config.Constant;
import com.kakacl.product_service.config.Constants;
import com.kakacl.product_service.controller.BaseController;
import com.kakacl.product_service.service.BackCardService;
import com.kakacl.product_service.utils.ErrorCode;
import com.kakacl.product_service.utils.Resp;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* @author wangwei
* @version v1.0.0
* @description 我的收入控制器
* @date 2019-01-11
*/
@RestController
@RequestMapping("/api/rest/{version}/myincome")
public class MyInComeController extends BaseController {
@Autowired
private BackCardService backCardService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 添加銀行卡的同步鎖
private final static String countKey="redis:lock:add_back_num";
@RequestMapping(value = "addBackCard", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Resp addBackCard(HttpServletRequest request,
@RequestParam(name = "time", required = true)String time,
String token,
@RequestParam(name = "cardNum", required = true) String cardNum,
String name,
String phoneNum,
String idCard,
String opanCardBack) {
Map params = new HashMap<>();
String userId = getUserid(request);
System.out.println(userId);
// TODO 只有噹噹前key不存在的時候,SETNX 會成功 – 此時相當於獲取到可以對這個資源進行操作的同步鎖
final String key=String.format("redis:add_card_num:id:%s", userId +"");
Boolean res = true;
while(res){
String value = UUID.randomUUID().toString()+System.nanoTime();
res = stringRedisTemplate.opsForValue().setIfAbsent(key,value);
if (res) {
stringRedisTemplate.opsForValue().increment(countKey, 1L);
try {
// 執行業務
res = false;
// 1.查詢用戶是否已經綁定過相同的銀行卡,根據銀行卡判斷
params.put("card_num", cardNum);
List<Map> result = backCardService.selectBackCarcdExist(params);
if(result != null && result.size() > Constants.CONSTANT_0) {
// 已經有綁定過
log.info("基於redis實戰分佈式鎖-成功:stock={} 這個銀行卡已經有賬戶綁定過 ",cardNum);
return Resp.fail(ErrorCode.CODE_6010);
} else {
// 繼續執行
log.info("繼續執行:stock={} ",cardNum);
return Resp.success();
}
} catch (Exception e) {
return Resp.fail();
} finally {
//TODO:釋放鎖-釋放當時自己獲取到的鎖-value
String redisValue = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(redisValue) && redisValue.equals(value)){
stringRedisTemplate.delete(key);
}
}
} else{
res=true;
try{
Thread.sleep(1000L);
} catch (Exception e) {}
}
}
return Resp.fail(ErrorCode.CODE_9999);
}
}