Redis数据结构及Spring-data-redis API使用

一、Redis概述

1. 简介
  简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。

2. 为什么要用 redis?/为什么要用缓存?

主要从“高性能”和“高并发”这两点来看待这个问题。

高性能:
假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在数缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!用户访问缓存

高并发:
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
用户访问缓存避免经过数据库

3. 内存和硬盘的区别

  • 性质不同:内存是计算机的工作场所,硬盘用来存放暂时不用的信息;

  • 制作材料不同:内存是半导体材料制作,硬盘是磁性材料制作;

  • 信息保存不同:内存中的信息会随掉电而丢失,硬盘中的信息可以长久保存;

  • 容量不同:一般硬盘的容量都为1TB即931GB,而内存一般都为8GB;

  • 作用不同:内存是 CPU 和硬盘数据之间的缓冲,CPU只能读取内存里的数据,这样内存就变成了一个桥梁的作用,而硬盘是作为存储空间的。

4. 为什么要用redis而不用map做缓存?

问题:redis是key-value的形式,map也是,可以用Map替代redis吗?如果不能替代,有什么场景或需求是只有redis能实现的呢?

缓存分为本地缓存和分布式缓存。以java为例,使用自带的map或者guava实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着jvm的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不具有一致性。使用redis或memcached之类的称为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,缓存具有一致性。缺点是需要保持redis或memcached服务的高可用,整个程序架构上较为复杂。

  1. Redis 可以用几十 G 内存来做缓存,Map 不行,一般 JVM 也就分几个 G 数据就够大了;

  2. Redis 的缓存可以持久化,Map 是内存对象,程序一重启数据就没了;

  3. Redis 可以实现分布式的缓存,Map 只能存在创建它的程序里;

  4. Redis 可以处理每秒百万级的并发,是专业的缓存服务,Map 只是一个普通的对象;

  5. Redis 缓存有过期机制,Map 本身无此功能;

  6. Redis 有丰富的 API,Map 就简单太多了。


二、redis数据类型

Redis目前可以存储键与5种不同数据结构类型之间的映射,分别是:

  • String(字符串)、List(列表)、Hash(散列)、Set(集合)、Zset(有序集合)
结构类型结构存储的值结构的读写能力
String可以是字符串、整数或者浮点数对整个字符串或者字符串的其中一部分执行操作;对象和浮点数执行自增(increment)或者自减(decrement)
List一个链表,链表上的每个节点都包含了一个字符串从链表的两端推入或者弹出元素;根据偏移量对链表进行修剪(trim);读取单个或者多个元素;根据值来查找或者移除元素
Set包含字符串的无序收集器(unorderedcollection),并且被包含的每个字符串都是独一无二的、各不相同添加、获取、移除单个元素;检查一个元素是否存在于某个集合中;计算交集、并集、差集;从集合里卖弄随机获取元素
Hash包含键值对的无序散列表添加、获取、移除单个键值对;获取所有键值对
Zset字符串成员(member)与浮点数分值(score)之间的有序映射,元素的排列顺序由分值的大小决定添加、获取、删除单个元素;根据分值范围(range)或者成员来获取元素

三、Spring-data-redis介绍

在Java中通过Jedis来操作Redis,由于Jedis的操作过于底层,或者说封装得不够彻底,当我们要存储一个对象的时候,其实是比较麻烦的,所以使用spring-data-redis越来越流行。Spring-data-redis是Spring-Data项目的一个子项目,就是Spring在Jedis的基础上封装的工具,比Jedis更加易用,而且使得操作Redis以更加面向对象的方式。

RedisTemplate中定义了对5种数据结构操作:

  • redisTemplate.opsForValue(),操作string;
  • redisTemplate.opsForHash(),操作hash;
  • redisTemplate.opsForList(),操作list;
  • redisTemplate.opsForSet(),操作set;
  • redisTemplate.opsForZSet(),操作有序set。

四、RedisTemplate通用方法
/**
 * 判断缓存是否存在
 *
 * @param key
 */
public static boolean exists(String key) {
    return jedisUtil.redisTemplate.hasKey(key);
}

/**
 * 删除缓存
 *
 * @param key
 * @return if exists 1 else 0
 */
public static long delete(String key) {
    if (exists(key)) {
        jedisUtil.redisTemplate.delete(key);
        return 1;
    }
    return 0;
}

/**
 * 设置Key过期时间
 *
 * @param key
 * @param cacheSeconds
 */
public void setExpireTime(String key, Long cacheSeconds) {
    jedisUtil.redisTemplate.expire(key, cacheSeconds, TimeUnit.SECONDS);
}

/**
 * 获取Key过期时间
 *
 * @param key
 * @return
 */
public static Long getExpireTime(String key) {
    return jedisUtil.redisTemplate.getExpire(key, TimeUnit.SECONDS);
}

五、RedisTemplate操作String类型

public interface ValueOperations<K,V>

/**
 * 设置缓存
 *
 * @param key          键
 * @param value        值
 * @param cacheSeconds 超时时间,0为不超时
 * @return
 */
public static void setStr(String key, String value, Long cacheSeconds) {
    if (cacheSeconds != 0) {
        jedisUtil.redisTemplate.opsForValue().set(key, value, cacheSeconds, TimeUnit.SECONDS);
    } else {
        jedisUtil.redisTemplate.opsForValue().set(key, value);
    }
}

/**
 * 获取缓存(String)
 *
 * @param key
 * @return
 */
public static String getStr(String key) {
    if (exists(key)) {
        String value = jedisUtil.redisTemplate.opsForValue().get(key).toString();
        return StringUtil.notEmpty(value) && !"nil".equalsIgnoreCase(value) ? value : null;
    }
    return null;
}

/**
 * 设置缓存(T)
 *
 * @param key          键
 * @param value        值
 * @param cacheSeconds 超时时间,0为不超时
 * @return
 */
public static <T> void setValue(String key, T value, Long cacheSeconds) {
    if (cacheSeconds != 0) {
        jedisUtil.redisTemplate.opsForValue().set(key, value, cacheSeconds, TimeUnit.SECONDS);
    } else {
        jedisUtil.redisTemplate.opsForValue().set(key, value);
    }
}

/**
 * 获取缓存(Object)
 *
 * @param key 键
 * @return
 */
public static Object getObject(String key) {
    if (exists(key)) {
        return jedisUtil.redisTemplate.opsForValue().get(key);
    }
    return null;
}

/**
 * 如果键不存在则新增
 * 存在则不作修改
 *
 * @param key
 * @param value
 * @param cacheSeconds
 * @return
 */
public static boolean setIfAbsent(String key, String value, Long cacheSeconds) {
    boolean result = false;
    result = jedisUtil.redisTemplate.opsForValue().setIfAbsent(key, value);
    if (cacheSeconds != 0) {
        // 设置key失效时间
        jedisUtil.redisTemplate.expire(key, cacheSeconds, TimeUnit.SECONDS);
    }
    return result;
}

/**
 * 获取原来Key键对应的value并重新赋新值
 * 若原来Key键不存在则返回null,并且要新建Key再赋值
 *
 * @param key
 * @param value
 * @return
 */
public static String getAndSet(String key, String value, Long cacheSeconds) {
    String res = (String) jedisUtil.redisTemplate.opsForValue().getAndSet(key, value);
    if (cacheSeconds != 0) {
        jedisUtil.redisTemplate.expire(key, cacheSeconds, TimeUnit.SECONDS);
    }
    return res;
}

/**
 * 为多个key分别设置value
 * 已存在的key则覆盖value
 *
 * @param map
 */
public static void multiSet(Map<String, String> map) {
    jedisUtil.redisTemplate.opsForValue().multiSet(map);
}

/**
 * 以自增形式存储long类型value
 * 相同的key value值累加
 *
 * @param
 */
public static Long incrLong(String key, Long delta) {
    return jedisUtil.redisTemplate.opsForValue().increment(key, delta);
}

/**
 * 以自增形式存储doble类型value
 * 相同的key value值累加
 *
 * @param key
 */
public static Double incrDouble(String key, double delta) {
    return jedisUtil.redisTemplate.opsForValue().increment(key, delta);
}

六、RedisTemplate操作List列表

List是简单的字符串<String>列表,按照插入顺序排序,可以添加一个元素到列表的头部(左边)或者尾部(右边)
public interface ListOperations<K,V>,ListOperations专门操作list列表:

/**
 * 存储整个List<T>
 * 若key相同,则后list加入到前list
 * right批量添加在右边
 *
 * @param key
 * @param value
 * @param cacheSeconds
 */
public static <T> void setList(String key, List<T> value, Long cacheSeconds) {
    jedisUtil.redisTemplate.opsForList().rightPushAll(key, value);
    if (cacheSeconds != 0) {
        jedisUtil.redisTemplate.expire(key, cacheSeconds, TimeUnit.SECONDS);
    }
}

/**
 * 添加单个value到list
 *
 * @param key
 * @param value
 * @param cacheSeconds
 */
public static <T> void setListV(String key, T value, Long cacheSeconds) {
    jedisUtil.redisTemplate.opsForList().rightPush(key, value);
    if (cacheSeconds != 0) {
        jedisUtil.redisTemplate.expire(key, cacheSeconds, TimeUnit.SECONDS);
    }
}

/**
 * 返回Key对应的List长度
 * 如果Key不存在,则解释为空表,并返回0
 *
 * @param key
 * @return
 */
public static Long getSize(String key) {
    return jedisUtil.redisTemplate.opsForList().size(key);
}

/**
 * 返回指定范围内的元素
 *
 * @param key
 * @param start 开始 0
 * @param end   结束
 *              0 到 -1 代表全部长度
 */
public static <T> List<T> getList(String key, long start, long end) {
    if (exists(key)) {
        return jedisUtil.redisTemplate.opsForList().range(key, start, end);
    }
    return null;
}

/**
 * 获取list头部的第一条value
 *
 * @param key
 */
public static Object leftPopList(String key) {
    if (exists(key)) {
        return jedisUtil.redisTemplate.opsForList().leftPop(key);
    }
    return null;
}

七、RedisTemplate操作Hash散列

Redis的散列可以让用户将多个键值对存储到一个Redis键里面
public interface HashOperations<H,HK,HV>,HashOperations提供一系列方法操作hash:

/**
 * 获取Key键对应的哈希HashKey
 *
 * @param key
 * @param hashKey
 * @return
 */
public static Object getHashK(String key, String hashKey) {
    return jedisUtil.redisTemplate.opsForHash().get(key, hashKey);
}

/**
 * 删除Key键对应的哈希HashKey
 *
 * @param key
 * @param hashKey
 * @return
 */
public static Long delHashK(String key, String hashKey) {
    return jedisUtil.redisTemplate.opsForHash().delete(key, hashKey);
}

/**
 * 判断Key键对应的哈希HashKey是否存在
 *
 * @param key
 * @param hashKey
 * @return
 */
public static boolean hashKey(String key, String hashKey) {
    return jedisUtil.redisTemplate.opsForHash().hasKey(key, hashKey);
}

/**
 * 通过给定的delta增加散列HashKey的值(Long)
 *
 * @param key
 * @param hashKey
 * @param delta
 */
public static Long incrHashLong(String key, String hashKey, long delta) {
    return jedisUtil.redisTemplate.opsForHash().increment(key, hashKey, delta);
}

/**
 * 通过给定的delta增加散列HashKey的值(Double)
 *
 * @param key
 * @param hashKey
 * @param delta
 * @return
 */
public static Double incrHashDouble(String key, String hashKey, Double delta) {
    return jedisUtil.redisTemplate.opsForHash().increment(key, hashKey, delta);
}

/**
 * 存储 HashMap - Map<HashKey - (T)value>
 *
 * @param key
 * @param value
 * @param cacheSeconds
 * @param <T>
 */
public static <T> void setHM(String key, Map<String, T> value, Long cacheSeconds) {
    jedisUtil.redisTemplate.opsForHash().putAll(key, value);
    if (cacheSeconds != 0) {
        jedisUtil.redisTemplate.expire(key, cacheSeconds, TimeUnit.SECONDS);
    }
}

/**
 * 获取 HashMap - Map<HashKey - (T)value>
 *
 * @param key
 * @param <T>
 * @return
 */
public static <T> Map<String, T> getHM(String key) {
    Map<String, T> value = null;
    if (exists(key)) {
        value = jedisUtil.redisTemplate.opsForHash().entries(key);
    }
    return value;
}

/**
 * 存储Key键 - HashKey - Map<String, T>
 *
 * @param key
 * @param hashKey
 * @param value
 * @param <T>
 */
public static <T> void setHKMap(String key, String hashKey, Map<String, T> value) {
    jedisUtil.redisTemplate.opsForHash().put(key, hashKey, value);
}

/**
 * 获取HashKey - Map<String, Object>
 *
 * @param key
 * @return
 */
public static Map<String, Map<String, Object>> getHKMap(String key) {
    Map<String, Map<String, Object>> value = null;
    if (exists(key)) {
        jedisUtil.redisTemplate.opsForHash().entries(key);
    }
    return value;
}

/**
 * 存储Key键 - HashKey - List<T>
 *
 * @param key
 * @param hashKey
 * @param value
 * @param <T>
 */
public static <T> void setHKList(String key, String hashKey, List<T> value) {
    jedisUtil.redisTemplate.opsForHash().put(key, hashKey, value);
}

/**
 * 存储Key键 - 所有(HashKey - List<T>)Map集合
 *
 * @param key
 * @param value
 * @param cacheSeconds
 * @param <T>
 */
public static <T> void setMapListAll(String key, Map<String, List<T>> value, Long cacheSeconds) {
    jedisUtil.redisTemplate.opsForHash().putAll(key, value);
    if (cacheSeconds != 0) {
        jedisUtil.redisTemplate.expire(key, cacheSeconds, TimeUnit.SECONDS);
    }
}

/**
 * 获取HashKey - List<T>
 *
 * @param key
 * @return
 */
public static <T> Map<String, List<T>> getHKList(String key) {
    Map<String, List<T>> value = null;
    if (exists(key)) {
        value = jedisUtil.redisTemplate.opsForHash().entries(key);
    }
    return value;
}

/**
 * 存储Key键 - HashKey - T value
 *
 * @param key
 * @param hashKey
 * @param value
 * @param <T>
 */
public static <T> void setHKObject(String key, String hashKey, T value) {
    jedisUtil.redisTemplate.opsForHash().put(key, hashKey, value);
}

八、RedisTemplate操作Set集合

Redis的Set是String类型的无序集合,集合成员是唯一的,这就意味着集合中不能出现重复的数据。Set是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
public interface SetOperations<K,V>,SetOperations提供了对无序集合的一系列操作:

/**
 * 无序集合中添加元素,返回添加的个数
 *
 * @param strings
 * @return
 */
public static Long addSet(String key, String[] strings) {
    return jedisUtil.redisTemplate.opsForSet().add(key, strings);
}

/**
 * 返回无序集合的大小长度
 *
 * @param key
 * @return
 */
public static Long getSetSize(String key) {
    return jedisUtil.redisTemplate.opsForSet().size(key);
}

/**
 * 返回集合中的所有成员
 *
 * @param key
 * @param <T>
 * @return
 */
public static <T> Set<T> getMembers(String key) {
    return jedisUtil.redisTemplate.opsForSet().members(key);
}

/**
 * 随机获取Key对应无序集合中的一个元素
 *
 * @param key
 * @return
 */
public static Object getRanMembers(String key) {
    return jedisUtil.redisTemplate.opsForSet().randomMember(key);
}

/**
 * 判断value是否是对应集合的成员
 *
 * @param key
 * @param value
 * @return
 */
public static Boolean isMembers(String key, Object value) {
    return jedisUtil.redisTemplate.opsForSet().isMember(key, value);
}

/**
 * 移除集合中多个成员,并返回删除个数
 *
 * @param key
 * @param strings
 * @return
 */
public static Long removeMembers(String key, String[] strings) {
    return jedisUtil.redisTemplate.opsForSet().remove(key, strings);
}

/**
 * 将元素value从一个集合移动到另一个集合
 *
 * @param startKey
 * @param endKey
 * @param value
 * @return
 */
public static Boolean moveSet(String startKey, String endKey, Object value) {
    return jedisUtil.redisTemplate.opsForSet().move(startKey, value, endKey);
}

九、RedisTemplate操作Zset集合

Redis 有序集合Zset和无序集合Set一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数,Redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。
public interface ZSetOperations<K,V>

参考
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值