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"));
}
加锁和释放锁我在黑体字的地方标明了,这样就能并发去摘牌了。