Redis|Redis 数据类型 和 spring-data-redis使用实例

一、redis数据类型
Redis目前支持5种数据类型,分别是:
String(字符串)
List(列表)
Hash(字典)
Set(集合)
Sorted Set(有序集合)
1.String
Redis|Redis 数据类型 和 spring-data-redis使用实例
文章图片
image.png Redis中的字符串是一个字节序列。Redis中的字符串是二进制安全的,这意味着它们的长度不由任何特殊的终止字符决定。因此,可以在一个字符串中存储高达512兆字节的任何内容。
2.List
Redis|Redis 数据类型 和 spring-data-redis使用实例
文章图片
image.png Redis列表只是字符串列表,按插入顺序排序。您可以向Redis列表的头部或尾部添加元素。
其实,我觉得这个更像我们java的queue,一样的是先进先出的的原理,线程安全的。很多时候我们在不使用消息中间件的时候,也可以使用列表类型来代替,而且比较轻量
3.Hash
Redis|Redis 数据类型 和 spring-data-redis使用实例
文章图片
image.png Redis散列/哈希(Hashes)是键值对的集合。Redis散列/哈希是字符串字段和字符串值之间的映射。因此,它们用于表示对象。
哈希这个就跟我们java的hashMap很像了,将一个对象当做一个hashMap。对象的属性是key值,属性值是value值。我们可以通过这个数据类型很快的拿出指定的某一属性值,而不是一次将有用和无用的属性全部拿出
4.Set
Redis|Redis 数据类型 和 spring-data-redis使用实例
文章图片
image.png Redis集合是字符串的无序集合。在Redis中,您可以添加,删除和测试成员存在的时间O(1)复杂性。
这个数据类型,我个人觉得就真的仅仅是一个容器而已。他不需要排序,只需要知道数据是否存在。与List的最大区别应该就是有序和无序
5.Sorted Set
Redis|Redis 数据类型 和 spring-data-redis使用实例
文章图片
image.png Redis可排序集合类似于Redis集合,是不重复的字符集合。 不同之处在于,排序集合的每个成员都与分数相关联,这个分数用于按最小分数到最大分数来排序的排序集合。虽然成员是唯一的,但分数值可以重复。
抱歉这里数据是不齐全的,但是这真的是个很有用的数据类型。这个数据类型让我们可以根据score达到自己期望的排序。更关键的是,我们可以利用这个机制在redis中进行分页查询,这个我在后面会给出实例。
二、spring-data-redis
spring-data-redis就是spring在jedis的基础上封装的工具,总的来说感觉比jedis更加易用,而且在都是使用spring生态环境的的情况下,用spring自家的东西总是好的。
至于具体的怎么安装,搭建环境。这么简单的事情,我想就不用在这里废话了。主要是给出几个spring-data-redis 写的比较好的使用实例。
首先,我们在写redis的key值命名时推荐按照"业务名称:唯一值"这种格式来命名。其中 “:” 的作用就是用于分组的,不仅是为了让key业务属性更加清晰,而且在某些视图工具下,工具可以根据分号给你自动分组,更加易于查看,例如:
Redis|Redis 数据类型 和 spring-data-redis使用实例
文章图片
image.png 【Redis|Redis 数据类型 和 spring-data-redis使用实例】![Uploading image_984753.png . . .]
我的key全名是 “TXN_NUM_GENERATOR:DCORF” 但是我有一组string数据都是TXN_NUM_GENERATOR前缀,工具就会自动给我归类分组。这样我们查看起来会清晰不少。试想每个key都是并列的,当有10W个key,我们需要查找时那是多么恐怖的情况。
然后代码使用。可以使用一个枚举类将5种类型定义,如下
Redis|Redis 数据类型 和 spring-data-redis使用实例
文章图片
image.png 然后,可以根据业务属性建立对应的keyName

public enum CacheName {/** * 缓存类型 */ private CacheType type; /** * 缓存前缀 */ private String prefix; /** * 缓存匹配器 */ private String regex; /** * 过期时间 */ private long expiration; CacheName(CacheType cacheType, long expiration) { this.type = cacheType; this.expiration = expiration; this.prefix = this.name().concat(":"); this.regex = prefix.concat("*"); }public long getExpiration() { return expiration; }public String getPrefix() { return prefix; }public String getRegex() { return regex; }public CacheType getType() { return type; }/** * 1天,拍卖中的拍品 key:IN_AUCTION_LOT:lotId value:LotRedisDto TODO 检查生产没有后删除 */ //IN_AUCTION_LOT(CacheType.V, 86400),/** * 5秒,竞价锁 */ IN_AUCTION_LOT_BID_LOCK(CacheType.S, 5),/** * 5秒,竞价订单锁 */ IN_AUCTION_LOT_ORDER_LOCK(CacheType.S, 5),/** * 5秒,竞拍中拍品时间锁 */ IN_AUCTION_LOT_TIME_LOCK(CacheType.S, 5) ; }

在定义一个key的时候,我们就可以将其的数据类型和过期时间通过构造器定义。
以下是spring-data-redis 提供的五种数据类型的service
Redis|Redis 数据类型 和 spring-data-redis使用实例
文章图片
image.png 以下,附上部分使用代码
public interface RedisService {/** * 从redis获取String类型数据 * * @param cacheName 缓存名称 * @param key组成key的变量 * @return key对应value */ Object vGet(CacheUtils.CacheName cacheName, String key); /** * 获取指定缓存名称的String类型数据 * * @param cacheName缓存名称 * @param isRedisKey 是否是redis中的key true:是 false:否 * @param keys组成key的变量 * @return value列表 */ List vMultiGet(CacheUtils.CacheName cacheName, boolean isRedisKey, String... keys); /** * 往redis中存入String类型数据 * * @param cacheName 缓存名称 * @param key组成key的变量 * @param value要存入的数据 */ void vPut(CacheUtils.CacheName cacheName, String key, Object value); /** * 往redis中存入Set类型数据 * * @param cacheName 缓存名称 * @param key组成key的变量 * @param values要存入的数据 * @return 添加成功的数量 */ Long sPut(CacheUtils.CacheName cacheName, String key, Object... values); /** * 查询redis的Set类型中是否有指定对象 * * @param cacheName 缓存名称 * @param key组成key的变量 * @return true 存在,false不存在 */ Boolean sExist(CacheUtils.CacheName cacheName, String key, Object value); /** * 从redis的Set类型中删除数据 * * @param cacheName 缓存名称 * @param key组成key的变量 * @param values要删除的数据 * @return 删除成功的数量 */ Long sRemove(CacheUtils.CacheName cacheName, String key, Object... values); /** * 查询redis的Set类型中所有数据 * * @param cacheName 缓存名称 * @param key组成key的变量 * @return 数据列表 */ Set sGetAll(CacheUtils.CacheName cacheName, String key); /** * 无条件分页查询SortedSet中的全部数据 * * @param cacheName 缓存名称 * @param key组成key的变量 * @param pageable分页参数 * @param isAsctrue:升序 false:降序 * @return 成员列表 */ Set zGet(CacheUtils.CacheName cacheName, String key, Pageable pageable, boolean isAsc); /** * 按照分数条件分页查询SortedSet中的数据 * * @param cacheName 缓存名称 * @param key组成key的变量 * @param includeMin是否包含最小值 * @param minScore最小值 * @param includeMax是否包含最大值 * @param maxScore最大值 * @param pageable分页参数 * @param isAsctrue:升序 false:降序 * @return 成员列表 */ Set zGetByScore(CacheUtils.CacheName cacheName, String key, boolean includeMin, Double minScore, boolean includeMax, Double maxScore, Pageable pageable, boolean isAsc); }
实现类:
@Service("redisService") public class RedisServiceImpl implements RedisService {@Resource private RedisTemplate redisTemplate; /** * String(字符串)操作类 */ @Resource(name = "redisTemplate") private ValueOperations valueOps; /** * List(列表)操作类 */ @Resource(name = "redisTemplate") private ListOperations listOps; /** * Set(集合)操作类 */ @Resource(name = "redisTemplate") private SetOperations setOps; /** * SortedSet(有序集合)操作类 */ @Resource(name = "redisTemplate") private ZSetOperations zSetOps; /** * Hash(哈希表)操作类 */ @Resource(name = "redisTemplate") private HashOperations hashOps; @Override public Object vGet(CacheUtils.CacheName cacheName, String key) { if (cacheName.getType() != CacheUtils.CacheType.V) { return null; } return valueOps.get(cacheName.getPrefix().concat(key)); }@Override public List vMultiGet(CacheUtils.CacheName cacheName, boolean isRedisKey, String... keys) { if (cacheName.getType() != CacheUtils.CacheType.V) { return null; } if (CollectionUtilPlus.isNullOrEmptyArray(keys)) { return null; } Set cacheKeys = new HashSet<>(); for (String key : keys) { if (isRedisKey) { //redis中的key cacheKeys.add(key); } else { //组成key的变量 cacheKeys.add(cacheName.getPrefix().concat(key)); } } List result = valueOps.multiGet(cacheKeys); return result; }@Override public void vPut(CacheUtils.CacheName cacheName, String key, Object value) { if (cacheName.getType() != CacheUtils.CacheType.V) { return; } if (cacheName.getExpiration() > 0) { valueOps.set(cacheName.getPrefix().concat(key), value, cacheName.getExpiration(), TimeUnit.SECONDS); } else { valueOps.set(cacheName.getPrefix().concat(key), value); } }@Override public Long sPut(CacheUtils.CacheName cacheName, String key, Object... values) { if (cacheName.getType() != CacheUtils.CacheType.S) { return 0L; } if (CollectionUtilPlus.isNullOrEmptyArray(values)) { return 0L; } String cacheKey = cacheName.getPrefix().concat(key); Long result = setOps.add(cacheKey, values); if (cacheName.getExpiration() > 0) { redisTemplate.expire(cacheKey, cacheName.getExpiration(), TimeUnit.SECONDS); } return result; }@Override public Boolean sExist(CacheUtils.CacheName cacheName, String key, Object value) { if (cacheName.getType() != CacheUtils.CacheType.S) { return false; } String cacheKey = cacheName.getPrefix().concat(key); return setOps.isMember(cacheKey, value); }@Override public Long sRemove(CacheUtils.CacheName cacheName, String key, Object... values) { if (cacheName.getType() != CacheUtils.CacheType.S) { return null; } if (CollectionUtilPlus.isNullOrEmptyArray(values)) { return null; } String cacheKey = cacheName.getPrefix().concat(key); Long result = setOps.remove(cacheKey, values); if (cacheName.getExpiration() > 0) { redisTemplate.expire(cacheKey, cacheName.getExpiration(), TimeUnit.SECONDS); } return result; }@Override public Set sGetAll(CacheUtils.CacheName cacheName, String key) { if (cacheName.getType() != CacheUtils.CacheType.S) { return null; } String cacheKey = cacheName.getPrefix().concat(key); return setOps.members(cacheKey); }@Override public Set zGet(CacheUtils.CacheName cacheName, String key, Pageable pageable, boolean isAsc) { if (cacheName.getType() != CacheUtils.CacheType.Z) { return null; } long start = pageable.getOffset(); long end = pageable.getOffset() + pageable.getPageSize() - 1; if (isAsc) { return zSetOps.range(cacheName.getPrefix().concat(key), start, end); } else { return zSetOps.reverseRange(cacheName.getPrefix().concat(key), start, end); } }@Override @SuppressWarnings("unchecked") public Set zGetByScore(CacheUtils.CacheName cacheName, String key, boolean includeMin, Double minScore, boolean includeMax, Double maxScore, Pageable pageable, boolean isAsc) { if (cacheName.getType() != CacheUtils.CacheType.Z) { return null; }RedisZSetCommands.Range range = RedisZSetCommands.Range.range(); if(minScore != null){ if(includeMin){ range.gte(minScore); }else{ range.gt(minScore); } }if(maxScore != null){ if(includeMax){ range.lte(maxScore); }else{ range.lt(maxScore); } }RedisZSetCommands.Limit limit = RedisZSetCommands.Limit.limit(); limit.offset(pageable.getOffset()); limit.count(pageable.getPageSize()); RedisSerializer keySerializer = redisTemplate.getKeySerializer(); byte[] rawKey = keySerializer.serialize(cacheName.getPrefix().concat(key)); Set rawValues; if (isAsc) { rawValues = redisTemplate.execute(new RedisCallback>() { public Set doInRedis(RedisConnection connection) { return connection.zRangeByScore(rawKey, range, limit); } }, true); } else { rawValues = redisTemplate.execute(new RedisCallback>() { public Set doInRedis(RedisConnection connection) { return connection.zRevRangeByScore(rawKey, range, limit); } }, true); } RedisSerializer valueSerialize = redisTemplate.getValueSerializer(); return SerializationUtils.deserialize(rawValues, valueSerialize); }@Override public Boolean zPut(CacheUtils.CacheName cacheName, String key, Object value, double score) { if (cacheName.getType() != CacheUtils.CacheType.Z) { return Boolean.FALSE; } String cacheKey = cacheName.getPrefix().concat(key); Boolean result = zSetOps.add(cacheKey, value, score); if (cacheName.getExpiration() > 0) { redisTemplate.expire(cacheKey, cacheName.getExpiration(), TimeUnit.SECONDS); } return result; }@Override public Long lRightPush(CacheUtils.CacheName cacheName, String key, Object... values) { if (CacheUtils.CacheType.L != cacheName.getType()) { return 0L; } if (CollectionUtilPlus.isNullOrEmptyArray(values)) { return 0L; } String cacheKey = cacheName.getPrefix().concat(key); Long result = listOps.rightPushAll(cacheKey, values); if (cacheName.getExpiration() > 0) { redisTemplate.expire(cacheKey, cacheName.getExpiration(), TimeUnit.SECONDS); } return result; }@Override public Long lLeftPush(CacheUtils.CacheName cacheName, String key, Object... values) { if (CacheUtils.CacheType.L != cacheName.getType()) { return 0L; } if (CollectionUtilPlus.isNullOrEmptyArray(values)) { return 0L; } String cacheKey = cacheName.getPrefix().concat(key); Long result = listOps.leftPushAll(cacheKey, values); if (cacheName.getExpiration() > 0) { redisTemplate.expire(cacheKey, cacheName.getExpiration(), TimeUnit.SECONDS); } return result; }@Override public void lRemove(CacheUtils.CacheName cacheName, String key, Object... values) { if (CacheUtils.CacheType.L != cacheName.getType()) { return; } if (CollectionUtilPlus.isNullOrEmptyArray(values)) { return; }String cacheKey = cacheName.getPrefix().concat(key); for (Object value : values) { listOps.remove(cacheKey, 0, value); } if (cacheName.getExpiration() > 0) { redisTemplate.expire(cacheKey, cacheName.getExpiration(), TimeUnit.SECONDS); } }@Override public Object lLeftBlockPop(CacheUtils.CacheName cacheName, String key, long timeout, TimeUnit unit) { if (cacheName.getType() != CacheUtils.CacheType.L) { return null; } String cacheKey = cacheName.getPrefix().concat(key); Object obj = listOps.leftPop(cacheKey, timeout, unit); return obj; }@Override public Object lLeftPop(CacheUtils.CacheName cacheName, String key) { String cacheKey = cacheName.getPrefix().concat(key); Object value = https://www.it610.com/article/listOps.leftPop(cacheKey); return value; }@Override public void removeKey(CacheUtils.CacheName cacheName, String... keys) { List cacheKeys = new ArrayList<>(); for (String key : keys) { cacheKeys.add(cacheName.getPrefix().concat(key)); } redisTemplate.delete(cacheKeys); }@Override public Boolean existsKey(CacheUtils.CacheName cacheName, String key) { String cacheKey = cacheName.getPrefix().concat(key); Boolean result = redisTemplate.hasKey(cacheKey); return result; }@Override public Object hGet(CacheUtils.CacheName cacheName, String key, String field) { if (cacheName.getType() != CacheUtils.CacheType.H) { return null; } return hashOps.get(cacheName.getPrefix().concat(key), field); }@Override public void hPut(CacheUtils.CacheName cacheName, String key, String field, Object value) { if (cacheName.getType() != CacheUtils.CacheType.H) { return; } String cacheKey = cacheName.getPrefix().concat(key); hashOps.put(cacheKey, field, value); if (cacheName.getExpiration() > 0) { redisTemplate.expire(cacheKey, cacheName.getExpiration(), TimeUnit.SECONDS); } }}
还有许多spring-data-redis的实现方法,暂时未贴出。但是大概的使用方式,及思路都是一样的。可以按照现在的方式去自己实现想要的接口。

    推荐阅读