一、redis数据类型
Redis目前支持5种数据类型,分别是:
String(字符串)
List(列表)
Hash(字典)
Set(集合)
Sorted Set(有序集合)
1.String
Redis中的字符串是一个字节序列。Redis中的字符串是二进制安全的,这意味着它们的长度不由任何特殊的终止字符决定。因此,可以在一个字符串中存储高达512兆字节的任何内容。
2.List
Redis列表只是字符串列表,按插入顺序排序。您可以向Redis列表的头部或尾部添加元素。
其实,我觉得这个更像我们java的queue,一样的是先进先出的的原理,线程安全的。很多时候我们在不使用消息中间件的时候,也可以使用列表类型来代替,而且比较轻量
3.Hash
Redis散列/哈希(Hashes)是键值对的集合。Redis散列/哈希是字符串字段和字符串值之间的映射。因此,它们用于表示对象。
哈希这个就跟我们java的hashMap很像了,将一个对象当做一个hashMap。对象的属性是key值,属性值是value值。我们可以通过这个数据类型很快的拿出指定的某一属性值,而不是一次将有用和无用的属性全部拿出
4.Set
Redis集合是字符串的无序集合。在Redis中,您可以添加,删除和测试成员存在的时间O(1)复杂性。
这个数据类型,我个人觉得就真的仅仅是一个容器而已。他不需要排序,只需要知道数据是否存在。与List的最大区别应该就是有序和无序
5.Sorted Set
Redis可排序集合类似于Redis集合,是不重复的字符集合。 不同之处在于,排序集合的每个成员都与分数相关联,这个分数用于按最小分数到最大分数来排序的排序集合。虽然成员是唯一的,但分数值可以重复。
抱歉这里数据是不齐全的,但是这真的是个很有用的数据类型。这个数据类型让我们可以根据score达到自己期望的排序。更关键的是,我们可以利用这个机制在redis中进行分页查询,这个我在后面会给出实例。
二、spring-data-redis
spring-data-redis就是spring在jedis的基础上封装的工具,总的来说感觉比jedis更加易用,而且在都是使用spring生态环境的的情况下,用spring自家的东西总是好的。
至于具体的怎么安装,搭建环境。这么简单的事情,我想就不用在这里废话了。主要是给出几个spring-data-redis 写的比较好的使用实例。
首先,我们在写redis的key值命名时推荐按照"业务名称:唯一值"这种格式来命名。其中 “:” 的作用就是用于分组的,不仅是为了让key业务属性更加清晰,而且在某些视图工具下,工具可以根据分号给你自动分组,更加易于查看,例如:
![Uploading image_984753.png . . .]
我的key全名是 “TXN_NUM_GENERATOR:DCORF” 但是我有一组string数据都是TXN_NUM_GENERATOR前缀,工具就会自动给我归类分组。这样我们查看起来会清晰不少。试想每个key都是并列的,当有10W个key,我们需要查找时那是多么恐怖的情况。
然后代码使用。可以使用一个枚举类将5种类型定义,如下
然后,可以根据业务属性建立对应的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
以下,附上部分使用代码
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<Object> 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<Object> sGetAll(CacheUtils.CacheName cacheName, String key);
/**
* 无条件分页查询SortedSet中的全部数据
*
* @param cacheName 缓存名称
* @param key 组成key的变量
* @param pageable 分页参数
* @param isAsc true:升序 false:降序
* @return 成员列表
*/
Set<Object> 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 isAsc true:升序 false:降序
* @return 成员列表
*/
Set<Object> 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<String, Object> redisTemplate;
/**
* String(字符串)操作类
*/
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> valueOps;
/**
* List(列表)操作类
*/
@Resource(name = "redisTemplate")
private ListOperations<String, Object> listOps;
/**
* Set(集合)操作类
*/
@Resource(name = "redisTemplate")
private SetOperations<String, Object> setOps;
/**
* SortedSet(有序集合)操作类
*/
@Resource(name = "redisTemplate")
private ZSetOperations<String, Object> zSetOps;
/**
* Hash(哈希表)操作类
*/
@Resource(name = "redisTemplate")
private HashOperations<String, String, Object> 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<Object> vMultiGet(CacheUtils.CacheName cacheName, boolean isRedisKey, String... keys) {
if (cacheName.getType() != CacheUtils.CacheType.V) {
return null;
}
if (CollectionUtilPlus.isNullOrEmptyArray(keys)) {
return null;
}
Set<String> cacheKeys = new HashSet<>();
for (String key : keys) {
if (isRedisKey) { //redis中的key
cacheKeys.add(key);
} else { //组成key的变量
cacheKeys.add(cacheName.getPrefix().concat(key));
}
}
List<Object> 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<Object> 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<Object> 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<Object> 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<byte[]> rawValues;
if (isAsc) {
rawValues = redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
public Set<byte[]> doInRedis(RedisConnection connection) {
return connection.zRangeByScore(rawKey, range, limit);
}
}, true);
} else {
rawValues = redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
public Set<byte[]> 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 = listOps.leftPop(cacheKey);
return value;
}
@Override
public void removeKey(CacheUtils.CacheName cacheName, String... keys) {
List<String> 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的实现方法,暂时未贴出。但是大概的使用方式,及思路都是一样的。可以按照现在的方式去自己实现想要的接口。