redis分布式锁处理并发摘牌,购买产品

1.项目背景,最近在公司有个项目其中有一步需要实现并发摘取市场上的理财产品,用数据库version乐观锁的话达不到要求,于是就想到了redis的分布式锁。

2.redisServer操作

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;


/**
 *
 * <p>Title: RedisService</p>
 * <p>Description: redis操作service</p>
* <p>Company: fzm</p>
 * @author 
 * @date 2018年7月2日下午7:43:43
 */
@Service
public class RedisService {

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 写入缓存
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 写入缓存设置时效时间
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 不存在写入成功,存在写入不成功
     * @param key
     * @param value
     * @return
     */
    public boolean setNx(String key,String value){
        boolean result = false;
        try {
            ValueOperations<Serializable, String> operations = redisTemplate.opsForValue();
            result =operations.setIfAbsent(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    public String getSet(String key,String value){
        String result = null;
        try {
            ValueOperations<Serializable, String> operations = redisTemplate.opsForValue();
            result = operations.getAndSet(key,value);
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 批量删除对应的value
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除key
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0) {
            redisTemplate.delete(keys);
        }
    }
    /**
     * 删除对应的value
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }
    /**
     * 判断缓存中是否有对应的value
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }
    /**
     * 读取缓存
     * @param key
     * @return
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    /**
     * 根据锁的key获得string
     * @param key
     * @return
     */
    public String lockGet(String key){
        String result = null;
        ValueOperations<Serializable, String> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }
    /**
     * 哈希 添加
     * @param key
     * @param hashKey
     * @param value
     */
    public void hmSet(String key, Object hashKey, Object value){
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.put(key,hashKey,value);
    }

    /**
     * 哈希获取数据
     * @param key
     * @param hashKey
     * @return
     */
    public Object hmGet(String key, Object hashKey){
        HashOperations<String, Object, Object>  hash = redisTemplate.opsForHash();
        return hash.get(key,hashKey);
    }

    /**
     * 列表添加
     * @param k
     * @param v
     */
    public void lPush(String k,Object v){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k,v);
    }

    /**
     * 列表获取
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k,l,l1);
    }

    /**
     * 集合添加
     * @param key
     * @param value
     */
    public void add(String key,Object value){
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.add(key,value);
    }

    /**
     * 集合获取
     * @param key
     * @return
     */
    public Set<Object> setMembers(String key){
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * 有序集合添加
     * @param key
     * @param value
     * @param scoure
     */
    public void zAdd(String key,Object value,double scoure){
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.add(key,value,scoure);
    }

    /**
     * 有序集合获取
     * @param key
     * @param scoure
     * @param scoure1
     * @return
     */
    public Set<Object> rangeByScore(String key,double scoure,double scoure1){
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.rangeByScore(key, scoure, scoure1);
    }
    public boolean expire(String key,int seconds){
        boolean result = redisTemplate.expire(key,seconds,TimeUnit.SECONDS);
        return result;
    }

}

3.redis分布式锁工具类

import cnzsqh.supplychain.common.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Description redis 分布式锁
 * @date 2018/8/7 13:28
 * @param
 * @return
 * @author yd
 */
@Component
public class DistributedLockUtil {
    @Autowired
    private RedisService redisService;

    /**
     * 获得锁
     * @param lockName
     * @return
     */
    public boolean lock(String lockName) {
        boolean result = redisService.setNx(lockName, String.valueOf(System.currentTimeMillis() + 5000));
        if (result == true) {
            System.out.println(Thread.currentThread() + "加锁成功!");
            redisService.expire(lockName, 5);
            return true;
        } else {
            String lockValueA = redisService.lockGet(lockName);
            if (lockValueA != null && Long.parseLong(lockValueA) < System.currentTimeMillis()) {
                String lockValueB = redisService.getSet(lockName, String.valueOf(System.currentTimeMillis() + 5000));
                if (lockValueB == null || lockValueB.equals(lockValueA)) {
                    System.out.println(Thread.currentThread() + "加锁成功!");
                    redisService.expire(lockName, 5);
                    return true;
                }else {
                    return false;
                }
            }else {
                return false;
            }
        }
    }

    /**
     * 释放锁
     * @param lockName
     */
    public void unlock(String lockName){
        redisService.remove(lockName);
    }
}

4.业务加锁

@Override
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public ResponseResult Delisting(DelistingBo delistingBo, HttpServletRequest request) {
    //token取企业信息
    String token = request.getHeader("token");
    Enterprise enterprise = new Enterprise();
    FinanceProductSell sell=new FinanceProductSell();
    boolean result=false;
    try {
        enterprise = enterpriseService.getEnterpriseByToken(token);
        boolean use=userService.isRole(enterprise.getId(), EnterpriseTypeEnum.INVESTMENT_ENTERPRISE.getCode());
        if (use==false){
            return ResponseResult.build().fail(messageService.getCode("inverdtment.queryId.error.matching.code"),messageService.getMessage("inverdtment.queryId.error.matching.message"));
        }
    }catch (Exception e){
        return ResponseResult.build().fail(messageService.getCode("inverdtment.queryId.error.matching.code"),messageService.getMessage("inverdtment.queryId.error.matching.message"));
    }

    try{//第一次摘牌
        sell=financeProductSellMapper.getSurplusCirculation(delistingBo.getId());
        FinanceProduct financeProduct =financeProductMapper.selectById(delistingBo.getId());
        EnterpriseAccount enterpriseAccount=accountService.getUseableAccount(enterprise.getId());

        Map<String,Object> map = new HashMap<String, Object>();
        List<Integer> list = new ArrayList<>();
        list.add(FinanceStatusEnum.ON_LISTING.getCode());
        list.add(FinanceStatusEnum.ON_LISTING_DELISTING.getCode());
        map.put("nowTime", DateUtil.getTimeOfEastEight());
        map.put("list",list);
        map.put("enterpriseId",enterprise.getId());
        map.put("id",delistingBo.getId());
        IPage page=new Page();
         page = financeProductSellMapper.getForMaket(page,map);
        if(page.getRecords().size()==0){
            return ResponseResult.build().fail(messageService.getCode("product.not.online.code"),messageService.getMessage("product.not.online.message"));
        }
        if(financeProduct.getBuyMinMoney().compareTo(sell.getSurplusReleaseScale())==1){
            Map<String,Object> updatemap = new HashMap<String, Object>();
            updatemap.put("auditStatus",FinanceStatusEnum.WAIT_FOR_LIQUIDATION.getCode());
            updatemap.put("sellStatus", FinanceStatusEnum.WAIT_FOR_LIQUIDATION.getCode());
            updatemap.put("buyStatus", FinanceStatusEnum.WAIT_FOR_LIQUIDATION.getCode());
            updatemap.put("id",delistingBo.getId());
            financeProductSellMapper.updateExpire(updatemap);
            return ResponseResult.build().fail(messageService.getCode("product.not.online.code"),messageService.getMessage("product.not.online.message"));
        }
        if(enterpriseAccount.getMoney().compareTo(delistingBo.getAmount())==-1){
            return ResponseResult.build().fail(messageService.getCode("surplus.not.enough.code"),messageService.getMessage("surplus.not.enough.message"));
        }
        //判断摘牌金额是否是摘牌金额减去最低起购金额除以递增金额的整数倍
        if(delistingBo.getAmount().subtract(financeProduct.getBuyMinMoney()).divide(financeProduct.getBuyAscMoney(),0,BigDecimal.ROUND_HALF_UP).subtract(delistingBo.getAmount().subtract(financeProduct.getBuyMinMoney()).divide(financeProduct.getBuyAscMoney(), RoundingMode.DOWN)).compareTo(BigDecimal.ZERO)!=0&&delistingBo.getAmount().compareTo(financeProduct.getBuyMinMoney())==1){
            return ResponseResult.build().fail(messageService.getCode("pick.notless.asc.code"),messageService.getMessage("pick.notless.asc.message")+ financeProduct.getBuyAscMoney());
        }
        if(delistingBo.getAmount().compareTo(financeProduct.getBuyMinMoney())==-1) {
            return ResponseResult.build().fail(messageService.getMessage("pick.notless.min.message") + financeProduct.getBuyMinMoney()).code(messageService.getCode("pick.notless.min.code"));
        }
        if(sell.getSurplusReleaseScale().compareTo(delistingBo.getAmount())==-1){
            return ResponseResult.build().fail(messageService.getMessage("pick.notmore.max.message") + sell.getSurplusReleaseScale()).code(messageService.getCode("pick.notmore.max.code"));
        }
        if(sell.getStatus()!=FinanceStatusEnum.ON_LISTING.getCode()&&sell.getStatus()!=FinanceStatusEnum.ON_LISTING_DELISTING.getCode()){
            return ResponseResult.build().fail(messageService.getCode("product.not.online.code"),messageService.getMessage("product.not.online.message"));
        }
        if(sell.getSubscriptions().hashCode()==sell.getBuyMaxUser()||sell.getSurplusReleaseScale().hashCode()==0.00){
            return ResponseResult.build().fail(messageService.getCode("product.picked.all.code"),messageService.getMessage("product.picked.all.message"));
        }
        if(financeProduct.getReleaseInstitution()==enterprise.getId()){
            return ResponseResult.build().fail(messageService.getCode("warranty.mine.error.code"),messageService.getMessage("warranty.mine.error.message"));
        }

        boolean lockResult =distributedLockUtil.lock(delistingBo.getId());
        FinanceProductSell financeProductSell=new FinanceProductSell();
        if(lockResult==false){
            Thread.sleep(Random.getLimitedRandom(6000,1000));
            lockResult =distributedLockUtil.lock(delistingBo.getId());
            if(lockResult==false){
                return ResponseResult.build().fail(messageService.getCode("pick.busy.fail.code"),messageService.getMessage("pick.busy.fail.message"));
            }
            if (lockResult==true){
                financeProductSell=financeProductSellMapper.getSurplusCirculation(delistingBo.getId());
            }
        }else if (lockResult==true){
             financeProductSell=financeProductSellMapper.getSurplusCirculation(delistingBo.getId());
        }

            result =financeProductBuyService.Buy(delistingBo,enterprise,financeProductSell);
        if(result==false) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.build().fail(messageService.getCode("picked.fail.code"),messageService.getMessage("picked.fail.message"));
        }
        distributedLockUtil.unlock(delistingBo.getId());
    }catch (Exception e){
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        return ResponseResult.build().fail(messageService.getCode("picked.fail.code"),messageService.getMessage("picked.fail.message"));
    }
    return ResponseResult.build().success(messageService.getMessage("picked.success.message"));

}

加锁和释放锁我在黑体字的地方标明了,这样就能并发去摘牌了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值