Skip to content

Commit d00134f

Browse files
committed
fix: 修复并发多从连接池获取jedis阻塞的问题
1 parent d7c5049 commit d00134f

File tree

1 file changed

+51
-30
lines changed

1 file changed

+51
-30
lines changed

src/main/java/cn/codingxiaxw/dao/cache/RedisDao.java

+51-30
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,23 @@ public RedisDao(String ip, int port) {
2323

2424
private RuntimeSchema<Seckill> schema = RuntimeSchema.createFrom(Seckill.class);
2525

26+
public Seckill getSeckill(long seckillId) {
27+
return getSeckill(seckillId, null);
28+
}
29+
2630
/**
2731
* 从redis获取信息
2832
*
2933
* @param seckillId id
3034
* @return 如果不存在,则返回null
3135
*/
32-
public Seckill getSeckill(long seckillId) {
36+
public Seckill getSeckill(long seckillId, Jedis jedis) {
37+
boolean hasJedis = jedis != null;
3338
//redis操作逻辑
3439
try {
35-
Jedis jedis = jedisPool.getResource();
40+
if (!hasJedis) {
41+
jedis = jedisPool.getResource();
42+
}
3643
try {
3744
String key = getSeckillRedisKey(seckillId);
3845
//并没有实现哪部序列化操作
@@ -48,7 +55,9 @@ public Seckill getSeckill(long seckillId) {
4855
return seckill;
4956
}
5057
} finally {
51-
jedis.close();
58+
if (!hasJedis) {
59+
jedis.close();
60+
}
5261
}
5362
} catch (Exception e) {
5463

@@ -65,38 +74,41 @@ public Seckill getSeckill(long seckillId) {
6574
* @return 返回商品信息
6675
*/
6776
public Seckill getOrPutSeckill(long seckillId, Function<Long, Seckill> getDataFromDb) {
68-
Seckill seckill = getSeckill(seckillId);
69-
if (seckill != null) {
70-
return seckill;
71-
}
7277

7378
String lockKey = "seckill:locks:getSeckill:" + seckillId;
7479
String lockRequestId = UUID.randomUUID().toString();
7580
Jedis jedis = jedisPool.getResource();
76-
// 尝试获取锁。
77-
// 锁过期时间是防止程序突然崩溃来不及解锁,而造成其他线程不能获取锁的问题。过期时间是业务容忍最长时间。
78-
boolean getLock = JedisUtils.tryGetDistributedLock(jedis, lockKey, lockRequestId, 1000);
79-
if (getLock) {
80-
// 获取到锁,从数据库拿数据, 然后存redis
81-
try {
82-
seckill = getDataFromDb.apply(seckillId);
83-
putSeckill(seckill);
84-
} catch (Exception ignored) {
85-
} finally {
86-
// 无论如何,最后要去解锁
87-
JedisUtils.releaseDistributedLock(jedis, lockKey, lockRequestId);
88-
}
89-
return seckill;
90-
}
9181

92-
// 获取不到锁,睡一下,等会再出发。sleep的时间需要斟酌,主要看业务处理速度
9382
try {
94-
Thread.sleep(100);
95-
} catch (InterruptedException e) {
96-
e.printStackTrace();
97-
}
98-
return getOrPutSeckill(seckillId, getDataFromDb);
83+
// 循环直到获取到数据
84+
while (true) {
85+
Seckill seckill = getSeckill(seckillId, jedis);
86+
if (seckill != null) {
87+
return seckill;
88+
}
89+
// 尝试获取锁。
90+
// 锁过期时间是防止程序突然崩溃来不及解锁,而造成其他线程不能获取锁的问题。过期时间是业务容忍最长时间。
91+
boolean getLock = JedisUtils.tryGetDistributedLock(jedis, lockKey, lockRequestId, 1000);
92+
if (getLock) {
93+
// 获取到锁,从数据库拿数据, 然后存redis
94+
seckill = getDataFromDb.apply(seckillId);
95+
putSeckill(seckill, jedis);
96+
return seckill;
97+
}
9998

99+
// 获取不到锁,睡一下,等会再出发。sleep的时间需要斟酌,主要看业务处理速度
100+
try {
101+
Thread.sleep(100);
102+
} catch (InterruptedException ignored) {
103+
}
104+
}
105+
} catch (Exception ignored) {
106+
} finally {
107+
// 无论如何,最后要去解锁
108+
JedisUtils.releaseDistributedLock(jedis, lockKey, lockRequestId);
109+
jedis.close();
110+
}
111+
return null;
100112
}
101113

102114
/**
@@ -110,8 +122,15 @@ private String getSeckillRedisKey(long seckillId) {
110122
}
111123

112124
public String putSeckill(Seckill seckill) {
125+
return putSeckill(seckill, null);
126+
}
127+
128+
public String putSeckill(Seckill seckill, Jedis jedis) {
129+
boolean hasJedis = jedis != null;
113130
try {
114-
Jedis jedis = jedisPool.getResource();
131+
if (!hasJedis) {
132+
jedis = jedisPool.getResource();
133+
}
115134
try {
116135
String key = getSeckillRedisKey(seckill.getSeckillId());
117136
byte[] bytes = ProtostuffIOUtil.toByteArray(seckill, schema,
@@ -122,7 +141,9 @@ public String putSeckill(Seckill seckill) {
122141

123142
return result;
124143
} finally {
125-
jedis.close();
144+
if (!hasJedis) {
145+
jedis.close();
146+
}
126147
}
127148
} catch (Exception e) {
128149

0 commit comments

Comments
 (0)