Authored by LUOXC

refactor

1 -package com.yohoufo.common.cache;  
2 -  
3 -import com.google.common.collect.Lists;  
4 -import com.yoho.core.redis.cluster.annotation.Redis;  
5 -import com.yoho.core.redis.cluster.operations.nosync.YHRedisTemplate;  
6 -import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;  
7 -import lombok.extern.slf4j.Slf4j;  
8 -import org.springframework.data.redis.core.script.DefaultRedisScript;  
9 -import org.springframework.data.redis.core.script.RedisScript;  
10 -import org.springframework.stereotype.Service;  
11 -  
12 -import java.util.concurrent.TimeUnit;  
13 -  
14 -@Service  
15 -@Slf4j  
16 -public class RedisLock {  
17 -  
18 - private static final Long RELEASE_SUCCESS = 1L;  
19 -  
20 - private static final String ACQUIRE_SUCCESS = "OK";  
21 -  
22 - @Redis("gwNoSyncRedis")  
23 - private YHRedisTemplate redis;  
24 -  
25 - public boolean acquire(RedisKeyBuilder keyBuilder, String value, final long timeout, final TimeUnit unit) {  
26 - try {  
27 - String script = "return redis.call('SET', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) ";  
28 - RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);  
29 - String key = keyBuilder.getKey();  
30 - String result = redis.getStringRedisTemplate().execute(redisScript, Lists.newArrayList(key),  
31 - value, String.valueOf(unit.toMillis(timeout)));  
32 - return ACQUIRE_SUCCESS.equals(result);  
33 - } catch (Exception e) {  
34 - return false;  
35 - }  
36 - }  
37 -  
38 - public void release(RedisKeyBuilder key, String value) {  
39 - try {  
40 - deleteKeyIfValueEquals(key, value);  
41 - } catch (Exception e) {  
42 - try {  
43 - deleteKeyIfValueEquals(key, value);  
44 - } catch (Exception e1) {  
45 - log.warn("release lock fail, key is {} value is {}", key, value);  
46 - }  
47 - }  
48 - }  
49 -  
50 - private boolean deleteKeyIfValueEquals(RedisKeyBuilder keyBuilder, String value) {  
51 - String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";  
52 - RedisScript<Long> redisScript = new DefaultRedisScript(script, Long.class);  
53 - String key = keyBuilder.getKey();  
54 - Long result = redis.getStringRedisTemplate().execute(redisScript, Lists.newArrayList(key), value);  
55 - if (RELEASE_SUCCESS.equals(result)) {  
56 - log.info("release lock ok, key is {} value is {}", key, value);  
57 - return true;  
58 - } else {  
59 - log.info("release lock ko, key is {} value is {}", key, value);  
60 - return false;  
61 - }  
62 - }  
63 -  
64 -  
65 -}  
  1 +package com.yohoufo.common.lock;
  2 +
  3 +import com.google.common.collect.Lists;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.data.redis.core.RedisTemplate;
  6 +import org.springframework.data.redis.core.script.DefaultRedisScript;
  7 +import org.springframework.data.redis.core.script.RedisScript;
  8 +
  9 +import java.util.Random;
  10 +import java.util.UUID;
  11 +import java.util.concurrent.TimeUnit;
  12 +
  13 +/**
  14 + * Redis分布式锁
  15 + * 使用 SET resource-name anystring NX EX max-lock-time 实现
  16 + * <p>
  17 + * 该方案在 Redis 官方 SET 命令页有详细介绍。
  18 + * http://doc.redisfans.com/string/set.html
  19 + * <p>
  20 + * 在介绍该分布式锁设计之前,我们先来看一下在从 Redis 2.6.12 开始 SET 提供的新特性,
  21 + * 命令 SET key value [EX seconds] [PX milliseconds] [NX|XX],其中:
  22 + * <p>
  23 + * EX seconds — 以秒为单位设置 key 的过期时间;
  24 + * PX milliseconds — 以毫秒为单位设置 key 的过期时间;
  25 + * NX — 将key 的值设为value ,当且仅当key 不存在,等效于 SETNX。
  26 + * XX — 将key 的值设为value ,当且仅当key 存在,等效于 SETEX。
  27 + * <p>
  28 + * 命令 SET resource-name anystring NX EX max-lock-time 是一种在 Redis 中实现锁的简单方法。
  29 + * <p>
  30 + * 客户端执行以上的命令:
  31 + * <p>
  32 + * 如果服务器返回 OK ,那么这个客户端获得锁。
  33 + * 如果服务器返回 NIL ,那么客户端获取锁失败,可以在稍后再重试。
  34 + */
  35 +@Slf4j
  36 +class DefaultRedisLock implements RedisLock {
  37 +
  38 + private static final String ACQUIRE_OK = "OK";
  39 +
  40 + private static final Long RELEASE_OK = 1L;
  41 +
  42 + private RedisTemplate<String, String> redisTemplate;
  43 +
  44 + private String key;
  45 +
  46 + /**
  47 + * 锁的有效时间(s)
  48 + */
  49 + private long expireTimeMillis;
  50 +
  51 + /**
  52 + * lua script
  53 + */
  54 + private String lockValue;
  55 +
  56 + /**
  57 + * 锁标记
  58 + */
  59 + private boolean locked;
  60 +
  61 + final Random random = new Random();
  62 +
  63 + DefaultRedisLock(Builder builder) {
  64 + this.redisTemplate = builder.redisTemplate;
  65 + this.key = builder.key;
  66 + this.expireTimeMillis = builder.expireTimeMillis;
  67 + }
  68 +
  69 + public boolean lock() {
  70 + updateLockValue();
  71 + while (true) {
  72 + if (acquire(lockValue, expireTimeMillis)) {
  73 + locked = true;
  74 + return true;
  75 + }
  76 + sleep(10, 50000);
  77 + }
  78 + }
  79 +
  80 + public boolean lock(long timeout, TimeUnit timeUnit) {
  81 + updateLockValue();
  82 + // 请求锁超时时间,纳秒
  83 + long timeoutNanos = timeUnit.toNanos(timeout);
  84 + // 系统当前时间,纳秒
  85 + long nowNanoTime = System.nanoTime();
  86 + while ((System.nanoTime() - nowNanoTime) < timeoutNanos) {
  87 + if (acquire(lockValue, expireTimeMillis)) {
  88 + locked = true;
  89 + // 上锁成功结束请求
  90 + return true;
  91 + }
  92 + // 每次请求等待一段时间
  93 + sleep(10, 50000);
  94 + }
  95 + return locked;
  96 + }
  97 +
  98 + public boolean tryLock() {
  99 + updateLockValue();
  100 + locked = acquireOr(lockValue, expireTimeMillis, false);
  101 + return locked;
  102 + }
  103 +
  104 + public boolean unlock() {
  105 + if (locked) {
  106 + if (releaseOr(lockValue, false)) {
  107 + locked = false;
  108 + return true;
  109 + } else {
  110 + return false;
  111 + }
  112 + }
  113 + return true;
  114 + }
  115 +
  116 + private boolean acquire(String value, long expireTimeMillis) {
  117 + String script = "return redis.call('SET', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) ";
  118 + RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);
  119 + String result = redisTemplate.execute(redisScript, Lists.newArrayList(key), value, String.valueOf(expireTimeMillis));
  120 + if (ACQUIRE_OK.equals(result)) {
  121 + log.info("acquire lock ok, key is {} value is {}", key, value);
  122 + return true;
  123 + } else {
  124 + log.info("acquire lock ko, key is {} value is {}", key, value);
  125 + return false;
  126 + }
  127 + }
  128 +
  129 + private boolean acquireOr(String value, long expireTimeMillis, boolean defaultValue) {
  130 + try {
  131 + return acquire(value, expireTimeMillis);
  132 + } catch (Exception e) {
  133 + log.info("release lock ko, key is {} value is {}", key, value, e);
  134 + return defaultValue;
  135 + }
  136 + }
  137 +
  138 + private boolean release(String value) {
  139 + String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
  140 + RedisScript<Long> redisScript = new DefaultRedisScript(script, Long.class);
  141 + Long result = redisTemplate.execute(redisScript, Lists.newArrayList(key), value);
  142 + if (RELEASE_OK.equals(result)) {
  143 + log.info("release lock ok, key is {} value is {}", key, value);
  144 + return true;
  145 + } else {
  146 + log.info("release lock ko, key is {} value is {}", key, value);
  147 + return false;
  148 + }
  149 + }
  150 +
  151 + private boolean releaseOr(String value, boolean defaultValue) {
  152 + try {
  153 + return release(value);
  154 + } catch (Exception e) {
  155 + // try once
  156 + try {
  157 + return release(value);
  158 + } catch (Exception e2) {
  159 + log.info("release lock ko, key is {} value is {}", key, value, e2);
  160 + return defaultValue;
  161 + }
  162 + }
  163 + }
  164 +
  165 + private void updateLockValue() {
  166 + lockValue = UUID.randomUUID().toString();
  167 + }
  168 +
  169 + /**
  170 + * 线程等待时间
  171 + *
  172 + * @param millis 毫秒
  173 + * @param nanos 纳秒
  174 + */
  175 + private void sleep(long millis, int nanos) {
  176 + try {
  177 + Thread.sleep(millis, random.nextInt(nanos));
  178 + } catch (InterruptedException e) {
  179 + log.info("lock {} sleep interrupted ", key, e);
  180 + }
  181 + }
  182 +
  183 +
  184 +}
  1 +package com.yohoufo.common.lock;
  2 +
  3 +import org.springframework.data.redis.core.RedisTemplate;
  4 +
  5 +import java.util.concurrent.TimeUnit;
  6 +
  7 +
  8 +public interface RedisLock {
  9 +
  10 + /**
  11 + * 阻塞方式的获取锁
  12 + *
  13 + * @return 是否成功获得锁
  14 + */
  15 + boolean lock();
  16 +
  17 + /**
  18 + * 获取锁 超时返回
  19 + *
  20 + * @return
  21 + */
  22 + boolean lock(long timeout, TimeUnit timeUnit);
  23 +
  24 + /**
  25 + * 尝试获取锁 立即返回
  26 + *
  27 + * @return 是否成功获得锁
  28 + */
  29 + boolean tryLock();
  30 +
  31 + /**
  32 + * 解锁
  33 + */
  34 + boolean unlock();
  35 +
  36 + static Builder builder() {
  37 + return new Builder();
  38 + }
  39 +
  40 + static RedisLock create(RedisTemplate redisTemplate, String key, long expireTime, TimeUnit timeUnit) {
  41 + return builder()
  42 + .redisTemplate(redisTemplate)
  43 + .key(key)
  44 + .expireTime(expireTime, timeUnit)
  45 + .build();
  46 + }
  47 +
  48 +
  49 + class Builder {
  50 +
  51 + RedisTemplate redisTemplate;
  52 +
  53 + String key;
  54 +
  55 + long expireTimeMillis;
  56 +
  57 + private Builder() {
  58 +
  59 + }
  60 +
  61 + public Builder redisTemplate(RedisTemplate redisTemplate) {
  62 + this.redisTemplate = redisTemplate;
  63 + return this;
  64 + }
  65 +
  66 + public Builder key(String key) {
  67 + this.key = key;
  68 + return this;
  69 + }
  70 +
  71 + public Builder expireTime(long expireTime, TimeUnit timeUnit) {
  72 + this.expireTimeMillis = timeUnit.toMillis(expireTime);
  73 + return this;
  74 + }
  75 +
  76 + public RedisLock build() {
  77 + return new DefaultRedisLock(this);
  78 + }
  79 + }
  80 +
  81 +}
  82 +
  1 +package com.yohoufo.common.lock;
  2 +
  3 +import com.yoho.core.redis.cluster.annotation.Redis;
  4 +import com.yoho.core.redis.cluster.operations.nosync.YHRedisTemplate;
  5 +import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.springframework.stereotype.Service;
  8 +
  9 +import java.util.concurrent.TimeUnit;
  10 +
  11 +@Service
  12 +@Slf4j
  13 +public class RedisLockFactory {
  14 +
  15 + @Redis("gwNoSyncRedis")
  16 + private YHRedisTemplate redis;
  17 +
  18 + public RedisLock newLock(RedisKeyBuilder keyBuilder, final long timeout, final TimeUnit unit) {
  19 + return RedisLock.create(redis.getStringRedisTemplate(), keyBuilder.getKey(), timeout, unit);
  20 + }
  21 +
  22 +}
@@ -5,11 +5,9 @@ import com.yohoufo.common.ApiResponse; @@ -5,11 +5,9 @@ import com.yohoufo.common.ApiResponse;
5 import com.yohoufo.common.annotation.IgnoreSession; 5 import com.yohoufo.common.annotation.IgnoreSession;
6 import com.yohoufo.common.annotation.IgnoreSignature; 6 import com.yohoufo.common.annotation.IgnoreSignature;
7 import com.yohoufo.common.annotation.InnerApi; 7 import com.yohoufo.common.annotation.InnerApi;
8 -import com.yohoufo.common.cache.RedisLock;  
9 -import com.yohoufo.common.exception.UfoServiceException; 8 +import com.yohoufo.common.lock.RedisLock;
  9 +import com.yohoufo.common.lock.RedisLockFactory;
10 import com.yohoufo.common.utils.ExecutorServiceUtils; 10 import com.yohoufo.common.utils.ExecutorServiceUtils;
11 -import com.yohoufo.common.utils.RandomUtil;  
12 -import com.yohoufo.order.model.QuickDeliverOrderContext;  
13 import com.yohoufo.order.model.request.TransferMoneyRequest; 11 import com.yohoufo.order.model.request.TransferMoneyRequest;
14 import com.yohoufo.order.service.impl.TransferService; 12 import com.yohoufo.order.service.impl.TransferService;
15 import com.yohoufo.order.utils.NamedThreadFactory; 13 import com.yohoufo.order.utils.NamedThreadFactory;
@@ -36,7 +34,7 @@ public class OrderHelpController { @@ -36,7 +34,7 @@ public class OrderHelpController {
36 private TransferService transferService; 34 private TransferService transferService;
37 35
38 @Autowired 36 @Autowired
39 - private RedisLock redisLock; 37 + private RedisLockFactory redisLockFactory;
40 38
41 /** 39 /**
42 * 转账 40 * 转账
@@ -64,7 +62,7 @@ public class OrderHelpController { @@ -64,7 +62,7 @@ public class OrderHelpController {
64 60, TimeUnit.SECONDS, 62 60, TimeUnit.SECONDS,
65 new ArrayBlockingQueue<>(1000), NamedThreadFactory.newThreadFactory("test")); 63 new ArrayBlockingQueue<>(1000), NamedThreadFactory.newThreadFactory("test"));
66 64
67 - IntStream.range(0, 10) 65 + IntStream.range(0, 100)
68 .forEach(i -> executorService.submit(() -> lockTest(key))); 66 .forEach(i -> executorService.submit(() -> lockTest(key)));
69 ExecutorServiceUtils.shutdownAndAwaitTermination(executorService); 67 ExecutorServiceUtils.shutdownAndAwaitTermination(executorService);
70 return new ApiResponse.ApiResponseBuilder() 68 return new ApiResponse.ApiResponseBuilder()
@@ -77,18 +75,18 @@ public class OrderHelpController { @@ -77,18 +75,18 @@ public class OrderHelpController {
77 RedisKeyBuilder redisLockKey = RedisKeyBuilder.newInstance() 75 RedisKeyBuilder redisLockKey = RedisKeyBuilder.newInstance()
78 .appendFixed("ufo:order:lock:test:") 76 .appendFixed("ufo:order:lock:test:")
79 .appendVar(key); 77 .appendVar(key);
80 - String value = UUID.randomUUID().toString();  
81 - if (redisLock.acquire(redisLockKey, value, 5, TimeUnit.SECONDS)) { 78 + RedisLock lock = redisLockFactory.newLock(redisLockKey,5, TimeUnit.SECONDS);
  79 + if (lock.tryLock()) {
82 try { 80 try {
83 - log.info("lock test {}, {} i got the lock", key, value);  
84 - Thread.sleep(RandomUtils.nextInt(4000, 5000)); 81 + log.info("lock test {}, i got the lock", key);
  82 + Thread.sleep(RandomUtils.nextInt(10, 50));
85 } catch (InterruptedException e) { 83 } catch (InterruptedException e) {
86 84
87 } finally { 85 } finally {
88 - redisLock.release(redisLockKey, value); 86 + lock.unlock();
89 } 87 }
90 } else { 88 } else {
91 - log.info("lock test {}, {} i not got the lock", key, value); 89 + log.info("lock test {}, i not got the lock", key);
92 } 90 }
93 } 91 }
94 92
@@ -16,9 +16,9 @@ import com.yohobuy.ufo.model.order.resp.PageResp; @@ -16,9 +16,9 @@ import com.yohobuy.ufo.model.order.resp.PageResp;
16 import com.yohobuy.ufo.model.order.resp.SellerGoodsPageResp; 16 import com.yohobuy.ufo.model.order.resp.SellerGoodsPageResp;
17 import com.yohoufo.common.alarm.EventBusPublisher; 17 import com.yohoufo.common.alarm.EventBusPublisher;
18 import com.yohoufo.common.alarm.SmsAlarmEvent; 18 import com.yohoufo.common.alarm.SmsAlarmEvent;
19 -import com.yohoufo.common.cache.RedisLock; 19 +import com.yohoufo.common.lock.RedisLock;
  20 +import com.yohoufo.common.lock.RedisLockFactory;
20 import com.yohoufo.common.exception.UfoServiceException; 21 import com.yohoufo.common.exception.UfoServiceException;
21 -import com.yohoufo.common.utils.StringUtil;  
22 import com.yohoufo.dal.order.SellerOrderGoodsViewMapper; 22 import com.yohoufo.dal.order.SellerOrderGoodsViewMapper;
23 import com.yohoufo.dal.order.model.SellerOrderGoods; 23 import com.yohoufo.dal.order.model.SellerOrderGoods;
24 import com.yohoufo.order.model.QuickDeliverOrderContext; 24 import com.yohoufo.order.model.QuickDeliverOrderContext;
@@ -34,8 +34,6 @@ import com.yohoufo.order.service.seller.orderMeta.SellerOrderMetaService; @@ -34,8 +34,6 @@ import com.yohoufo.order.service.seller.orderMeta.SellerOrderMetaService;
34 import com.yohoufo.order.service.support.codegenerator.OrderCodeGenerator; 34 import com.yohoufo.order.service.support.codegenerator.OrderCodeGenerator;
35 import com.yohoufo.order.utils.LoggerUtils; 35 import com.yohoufo.order.utils.LoggerUtils;
36 import org.apache.commons.collections.CollectionUtils; 36 import org.apache.commons.collections.CollectionUtils;
37 -import org.apache.commons.lang3.RandomUtils;  
38 -import org.apache.commons.lang3.StringUtils;  
39 import org.slf4j.Logger; 37 import org.slf4j.Logger;
40 import org.springframework.beans.factory.annotation.Autowired; 38 import org.springframework.beans.factory.annotation.Autowired;
41 import org.springframework.stereotype.Service; 39 import org.springframework.stereotype.Service;
@@ -85,19 +83,19 @@ public class QuickDeliverGoodsService { @@ -85,19 +83,19 @@ public class QuickDeliverGoodsService {
85 private SellerNoticeFacade sellerNoticeFacade; 83 private SellerNoticeFacade sellerNoticeFacade;
86 84
87 @Autowired 85 @Autowired
88 - private RedisLock redisLock; 86 + private RedisLockFactory redisLockFactory;
89 87
90 public DepositPublishResp publish(QuickDeliverOrderSubmitReq req) { 88 public DepositPublishResp publish(QuickDeliverOrderSubmitReq req) {
91 RedisKeyBuilder redisLockKey = RedisKeyBuilder.newInstance() 89 RedisKeyBuilder redisLockKey = RedisKeyBuilder.newInstance()
92 .appendFixed("ufo:order:lock:publishQuickDeliverGoods:") 90 .appendFixed("ufo:order:lock:publishQuickDeliverGoods:")
93 .appendVar(req.getUid() + "-" + req.getStorageId()); 91 .appendVar(req.getUid() + "-" + req.getStorageId());
94 - String value = UUID.randomUUID().toString();  
95 - if (redisLock.acquire(redisLockKey, value,5, TimeUnit.SECONDS)) { 92 + RedisLock lock = redisLockFactory.newLock(redisLockKey,5,TimeUnit.SECONDS);
  93 + if (lock.tryLock()) {
96 try { 94 try {
97 QuickDeliverOrderContext qdoc = quickDeliverPublishProcessor.buildPublishCtx(req); 95 QuickDeliverOrderContext qdoc = quickDeliverPublishProcessor.buildPublishCtx(req);
98 return doPublish(qdoc); 96 return doPublish(qdoc);
99 } finally { 97 } finally {
100 - redisLock.release(redisLockKey,value); 98 + lock.unlock();
101 } 99 }
102 } else { 100 } else {
103 logger.warn("storage has publishing , {} ", redisLockKey); 101 logger.warn("storage has publishing , {} ", redisLockKey);
@@ -4,9 +4,9 @@ import com.alibaba.fastjson.JSONObject; @@ -4,9 +4,9 @@ import com.alibaba.fastjson.JSONObject;
4 import com.google.common.collect.Lists; 4 import com.google.common.collect.Lists;
5 import com.google.common.collect.Sets; 5 import com.google.common.collect.Sets;
6 import com.yoho.core.config.ConfigReader; 6 import com.yoho.core.config.ConfigReader;
7 -import com.yoho.core.redis.cluster.annotation.Redis;  
8 -import com.yoho.core.redis.cluster.operations.nosync.YHValueOperations;  
9 import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder; 7 import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
  8 +import com.yohoufo.common.lock.RedisLock;
  9 +import com.yohoufo.common.lock.RedisLockFactory;
10 import com.yohoufo.common.utils.DateUtil; 10 import com.yohoufo.common.utils.DateUtil;
11 import com.yohoufo.dal.order.BuyerOrderGoodsMapper; 11 import com.yohoufo.dal.order.BuyerOrderGoodsMapper;
12 import com.yohoufo.dal.order.SellerOrderMetaMapper; 12 import com.yohoufo.dal.order.SellerOrderMetaMapper;
@@ -59,8 +59,8 @@ public class HkAccountSettlement { @@ -59,8 +59,8 @@ public class HkAccountSettlement {
59 @Autowired 59 @Autowired
60 private SellerOrderMetaMapper sellerOrderMetaMapper; 60 private SellerOrderMetaMapper sellerOrderMetaMapper;
61 61
62 - @Redis("gwNoSyncRedis")  
63 - private YHValueOperations valueOperations; 62 + @Autowired
  63 + private RedisLockFactory redisLockFactory;
64 64
65 65
66 public void settle(Integer uid) { 66 public void settle(Integer uid) {
@@ -69,12 +69,11 @@ public class HkAccountSettlement { @@ -69,12 +69,11 @@ public class HkAccountSettlement {
69 RedisKeyBuilder redisLockKey = RedisKeyBuilder.newInstance() 69 RedisKeyBuilder redisLockKey = RedisKeyBuilder.newInstance()
70 .appendFixed("ufo:order:hkAccount:settle:") 70 .appendFixed("ufo:order:hkAccount:settle:")
71 .appendVar(uid + "-" + dealTime); 71 .appendVar(uid + "-" + dealTime);
72 - String redisLockValue = "Y";  
73 - if (redisLockValue.equals(valueOperations.get(redisLockKey))) { 72 + RedisLock redisLock = redisLockFactory.newLock(redisLockKey,5, TimeUnit.SECONDS);
  73 + if (!redisLock.tryLock()) {
74 log.info("{} settle fail, it already in the process", uid); 74 log.info("{} settle fail, it already in the process", uid);
75 return; 75 return;
76 } 76 }
77 - valueOperations.set(redisLockKey, redisLockValue, 5, TimeUnit.SECONDS);  
78 // 没有要打款的账单 77 // 没有要打款的账单
79 if (!tryLock(uid, dealTime)) { 78 if (!tryLock(uid, dealTime)) {
80 log.info("{} settle fail, it already in the process", uid); 79 log.info("{} settle fail, it already in the process", uid);
@@ -113,6 +112,7 @@ public class HkAccountSettlement { @@ -113,6 +112,7 @@ public class HkAccountSettlement {
113 log.info("{} settle, sun income is {} but limit {}", uid, sumIncome, limitAmount); 112 log.info("{} settle, sun income is {} but limit {}", uid, sumIncome, limitAmount);
114 releaseLockWithRetry(uid, dealTime); 113 releaseLockWithRetry(uid, dealTime);
115 } 114 }
  115 + redisLock.unlock();
116 } 116 }
117 117
118 private List<TradeBillResult> getTradeBillResults(Integer uid, List<TradeBills> tradeBills) { 118 private List<TradeBillResult> getTradeBillResults(Integer uid, List<TradeBills> tradeBills) {