springboot基于redis的分布式锁代码

时间:2019-01-11
本文章向大家介绍springboot基于redis的分布式锁代码,主要包括springboot基于redis的分布式锁代码使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

分布式锁,当前代码中, 会循环尝试执行获取锁对象,每一秒一次。

如果锁没有释放而退出,会导致死锁的现象, 在看官的场合中,可以对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);
    }
}