Redis
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
当系统需要在高并发访问的情况下,保证业务数据的正常处理,可借助于锁来保持指定业务的正常处理。如基于Redis的分布式锁和基于ZooKeeper的分布式锁等技术。
Redis锁
使用到Redis提到的SETNX命令、GETSET命令、GET命令
SETNX:将 key 的值设为 value ,当且仅当 key 不存在。
GETSET:将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
GET:返回 key 所关联的字符串值。
RedisUtil核心代码示例如下:
private StringRedisTemplate redisTemplate;
/**
* 加锁
* @param key
* @param value
* @return
*/
public boolean lock(String key, String value) {
if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
return true;
}
String currentValue = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentValue)
&& Long.parseLong(currentValue) < System.currentTimeMillis()) {
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(oldValue)
&& oldValue.equals(currentValue)) {
return true;
}
}
return false;
}
/**
* 解锁
*/
public void unLock(String key, String value) {
try {
String currentValue = redisTemplate.opsForValue().get(key);
if (StringUtils.isNotEmpty(currentValue)
&& value.equals(currentValue)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
} catch (Exception e) {
log.error("-- reids分布式锁 -- 解锁异常:{}", e);
}
}
业务使用代码示例
skillNum方法中使用了Redis分布式锁,确保业务正常处理(单次处理时长10秒,可根据实际需求做调整),保证单业务处理key的唯一性。
private RedisUtil redisUtil;
//加锁超时时间为10秒
private static final Integer TIMEOUT = 10 * 1000;
@Override
public void skillNum(String id) {
//加锁
long time = System.currentTimeMillis() + TIMEOUT;
if(!redisUtil.lock(id,String.valueOf(time))){
throw new BException("加锁中处理中,请稍后再试!",110);
}
//处理中....
//解锁
redisUtil.unLock(id,String.valueOf(time));
}