Redis|Redis 数据类型 和 spring-data-redis使用实例
一、redis数据类型
Redis目前支持5种数据类型,分别是:
String(字符串)
List(列表)
Hash(字典)
Set(集合)
Sorted Set(有序集合)
1.String
文章图片
image.png Redis中的字符串是一个字节序列。Redis中的字符串是二进制安全的,这意味着它们的长度不由任何特殊的终止字符决定。因此,可以在一个字符串中存储高达512兆字节的任何内容。
2.List
文章图片
image.png Redis列表只是字符串列表,按插入顺序排序。您可以向Redis列表的头部或尾部添加元素。
其实,我觉得这个更像我们java的queue,一样的是先进先出的的原理,线程安全的。很多时候我们在不使用消息中间件的时候,也可以使用列表类型来代替,而且比较轻量
3.Hash
文章图片
image.png Redis散列/哈希(Hashes)是键值对的集合。Redis散列/哈希是字符串字段和字符串值之间的映射。因此,它们用于表示对象。
哈希这个就跟我们java的hashMap很像了,将一个对象当做一个hashMap。对象的属性是key值,属性值是value值。我们可以通过这个数据类型很快的拿出指定的某一属性值,而不是一次将有用和无用的属性全部拿出
4.Set
文章图片
image.png Redis集合是字符串的无序集合。在Redis中,您可以添加,删除和测试成员存在的时间O(1)复杂性。
这个数据类型,我个人觉得就真的仅仅是一个容器而已。他不需要排序,只需要知道数据是否存在。与List的最大区别应该就是有序和无序
5.Sorted Set
文章图片
image.png Redis可排序集合类似于Redis集合,是不重复的字符集合。 不同之处在于,排序集合的每个成员都与分数相关联,这个分数用于按最小分数到最大分数来排序的排序集合。虽然成员是唯一的,但分数值可以重复。
抱歉这里数据是不齐全的,但是这真的是个很有用的数据类型。这个数据类型让我们可以根据score达到自己期望的排序。更关键的是,我们可以利用这个机制在redis中进行分页查询,这个我在后面会给出实例。
二、spring-data-redis
spring-data-redis就是spring在jedis的基础上封装的工具,总的来说感觉比jedis更加易用,而且在都是使用spring生态环境的的情况下,用spring自家的东西总是好的。
至于具体的怎么安装,搭建环境。这么简单的事情,我想就不用在这里废话了。主要是给出几个spring-data-redis 写的比较好的使用实例。
首先,我们在写redis的key值命名时推荐按照"业务名称:唯一值"这种格式来命名。其中 “:” 的作用就是用于分组的,不仅是为了让key业务属性更加清晰,而且在某些视图工具下,工具可以根据分号给你自动分组,更加易于查看,例如:
文章图片
image.png 【Redis|Redis 数据类型 和 spring-data-redis使用实例】![Uploading image_984753.png . . .]
我的key全名是 “TXN_NUM_GENERATOR:DCORF” 但是我有一组string数据都是TXN_NUM_GENERATOR前缀,工具就会自动给我归类分组。这样我们查看起来会清晰不少。试想每个key都是并列的,当有10W个key,我们需要查找时那是多么恐怖的情况。
然后代码使用。可以使用一个枚举类将5种类型定义,如下
文章图片
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
文章图片
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
实现类:
@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的实现方法,暂时未贴出。但是大概的使用方式,及思路都是一样的。可以按照现在的方式去自己实现想要的接口。
推荐阅读
- C语言学习心得|深度分析数据在内存中的存储形式
- c语言中字符型char数据在内存中占|c语言中字符型char数据在内存中占,互联网常识(在c语言中char型数据在内存中的储存形式为什么...)
- 在c语言中 char型数据在内存中的存储形式是,在c语言中char型数据在内存中的存储形式是什么(...)
- 数据在内存中是怎样储存的
- Flask框架|Flask框架——数据库配置及迁移同步
- 编程语言|Python干货宝典(如何处理Pandas中丢失的数据)
- 数据分析|Python | Pandas | 多列映射匹配到新列
- 【Netty】七、服务端读取数据流程 - 源码解读
- 上榜中国大数据企业50强,思迈特软件再夺多项荣誉
- 使用|使用 JavaScript Promise 读取 Github 某用户的数据