redis一般使用key--value的形式存值,将内存中的数据保存在磁盘中(in-memory),启动的时候再加载使用。
redis是单进程单线程,支持主从模式。具有会话缓存功能,具有发布/订阅功能。
Redis的LRU策略:
Redis在缓存的内存达到极限时,会优先选择最久未被访问的数据进行回收。具体回收策略通过maxmemory-policy配置项进行配置。
Redis优点:
1.性能好,redis中的数据读写速度快。
2.数据类型丰富,Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型
3.丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性
4.Redis支持数据的备份,即master-slave模式的数据备份
Spring集成Redis:
classpath:db.properties
public interface DistributionLock {
//加锁成功 返回加锁时间
public Long lock(String lockKey, String threadname);
//解锁 需要更加加锁时间判断是否有权限
public void unlock(String lockKey, long lockvalue, String threadname);
}
public class RedisDistributionLock implements DistributionLock{
@Autowired
private RedisTemplate redisTemplate;
private static final long LOCK_TIMEOUT = 60 * 1000; //加锁超时时间 单位毫秒 意味着加锁期间内执行完操作 如果未完成会有并发现象
private static final Logger LOG = Logger.getLogger(RedisDistributionLock.class); //redis锁日志
/**
* 取到锁加锁 取不到锁一直等待直到获得锁
*/
@Override
public synchronized Long lock(String lockKey, String threadname) {
LOG.info(threadname + "开始执行加锁");
while (true) { //循环获取锁
Long lock_timeout = System.currentTimeMillis() + LOCK_TIMEOUT + 1; //锁时间
if (redisTemplate.execute(new RedisCallback() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();
byte[] value = jdkSerializer.serialize(lock_timeout);
return connection.setNX(lockKey.getBytes(), value);
}
})) { //如果加锁成功
LOG.info(threadname + "加锁成功+1");
redisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS); //设置超时时间,释放内存
return lock_timeout;
}else {
Long currt_lock_timeout_Str = (Long) redisTemplate.opsForValue().get(lockKey); // redis里的时间
if (currt_lock_timeout_Str != null && currt_lock_timeout_Str < System.currentTimeMillis()) { //锁已经失效
// 判断是否为空,不为空的情况下,说明已经失效,如果被其他线程设置了值,则第二个条件判断是无法执行
Long old_lock_timeout_Str = (Long) redisTemplate.opsForValue().getAndSet(lockKey, lock_timeout);
// 获取上一个锁到期时间,并设置现在的锁到期时间
if (old_lock_timeout_Str != null && old_lock_timeout_Str.equals(currt_lock_timeout_Str)) {
// 如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁
LOG.info(threadname + "加锁成功+2");
redisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS); //设置超时时间,释放内存
return lock_timeout;//返回加锁时间
}
}
}
try {
LOG.info(threadname + "等待加锁,睡眠100毫秒");
TimeUnit.MILLISECONDS.sleep(100);//睡眠100毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public synchronized void unlock(String lockKey, long lockvalue, String threadname) {
LOG.info(threadname + "执行解锁==");//正常直接删除 如果异常关闭判断加锁会判断过期时间
Long currt_lock_timeout_Str = (Long) redisTemplate.opsForValue().get(lockKey); // redis里的时间
if (currt_lock_timeout_Str != null && currt_lock_timeout_Str == lockvalue) {//如果是加锁者 则删除锁 如果不是则等待自动过期 重新竞争加锁
redisTemplate.delete(lockKey); //删除键
LOG.info(threadname + "解锁成功---");
}
}
}
RedisTemplate操作:
public class RedisUnitTest extends BaseJunit4 {
/**
* 默认采用String序列化策略(key与value)
*/
@Resource(name = "redisTemplate_KVString")
private RedisTemplate redisTemplate_KVString;
/**
* Redis 可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为
* String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)
* Key值如无特殊要求,一般为String类型
*
*/
public void queryRedisValue(){
String key = "";
String value = "";
String value2 = "";
Map maps = new HashMap();
maps.put("key1","value1");
maps.put("key2","value2");
maps.put("key3","value3");
List keys = new ArrayList();
keys.add("key1");
keys.add("key2");
keys.add("key3");
redisTemplate_KVString.opsForValue().set(key, value, 10, TimeUnit.SECONDS);//设置key-value失效时间10s
redisTemplate_KVString.opsForValue().get(key);//根据key获取value,10秒的时限
redisTemplate_KVString.opsForValue().setIfAbsent(key, value);//false 已存在key/ true 之前不存在key
redisTemplate_KVString.opsForValue().multiSet(maps);//同时设置多个 key-value
redisTemplate_KVString.opsForValue().getAndSet(key, value2);//设置key的value值,并返回旧value
redisTemplate_KVString.opsForValue().multiGet(keys);//同时取出多个 key对应的value
redisTemplate_KVString.opsForValue().append(key, value);//key存在则将value追加到末尾,不存在则创建一个key-空串,再加到末尾
redisTemplate_KVString.opsForValue().get(key, 0, 3);//截取key 所对应的value字符串
redisTemplate_KVString.opsForValue().size(key);//返回key对应的value长度
redisTemplate_KVString.opsForHash();//操作hash
redisTemplate_KVString.opsForList();//操作list
redisTemplate_KVString.opsForSet();//操作set
redisTemplate_KVString.opsForZSet();//操作有序set
//如需将key在redis服务器中保存为文件夹类型,在文件夹名后加 : 号
String folder = "key:";
key = folder + 1;
redisTemplate_KVString.opsForValue().set(key, value);
}
}