一次redis悲观锁 实现 微信jssdk token缓存
(一)背景:
1 access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token,且每天有额度配额,最大调用次数限制
这一条决定:必须将access_token 缓存起来,否则每天都超标返回null
2 正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。
这一条决定:
(1)我们应将access_token 缓存7000秒,使用redis指定缓存时间是最好不过的
(2)先来看一下一般缓存代码:
String token = (String)stringRedisTemplate.opsForValue().get(ACCESS); if(token == null) { token = WeXinCodeUtils.getAccessToken(); stringRedisTemplate.opsForValue().set(ACCESS, token); System.out.println("request"); } else { System.out.println("cache"); }
先读后写,单线程下没有问题,输出:
request
cache
单在多线程下会有问题,而且会导致事故,比如:
B线程的请求token会导致A线程请求的token失效,A线程拿着失效的token,就失败了
对于这样的场景,我们都会想到两种方案:
1.悲观锁
这个方案可行,有点像单例模式,但是不应用于集群,同样会出事故:
synchronized不受多应用限制,导致应用A的token失效
故可以将synchronized替换为redis分布式锁
2.乐观锁
B线程请求token那会儿,A线程的token已经失效了,不管你乐观锁会报错,请求可不是数据库还给你token回滚,所以乐观锁在这个地方不适用,
故只能考虑分布式锁,有点像处理缓存击穿,这里是大并发场景,则是防大量请求同时爆到微信服务器,导致当日服务超次数限制。
(二)实现
1. 实现过程中,实践证明“正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。“不准确,
重复获取不会导致上次获取的access_token失效,获取后7200秒自然失效;
2. 本实例也不存在超高并发导致一秒内请求微信超限;
此2点决定:此次代码不考虑并发同步问题,一般代码处理即可,即:
一般缓存代码:
String token = (String)stringRedisTemplate.opsForValue().get(ACCESS); if(token == null) { token = WeXinCodeUtils.getAccessToken(); stringRedisTemplate.opsForValue().set(ACCESS, token); System.out.println("request"); } else { System.out.println("cache"); }