Redis需要学习的东西

1、RedisAtomicLong:获取自增的id封装类`https://blog.csdn.net/u014381863/article/details/50382179`

2、redis的事务:https://blog.csdn.net/qq_32331073/article/details/79884032

3、redis的方法封装

```java

public class RedisUtil implements ICache {

private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);

@Autowired
protected RedisTemplate<String, String> redisTemplate;

/**
* 队列操作 从队列左边放入
*
* @param queueName 键名称
* @param value 对象值
* @return
*/
@Override
public <T extends Object> boolean lPush(final String queueName, final T value) {
return redisTemplate.execute((RedisCallback<Boolean>)connection -> {
connection.lPush(queueName.getBytes(), serialize(value));
return true;
});
}

/**
* 从队列右边取出
*
* @param queueName 键名称
* @param <T> 对象类型
* @return
*/
@Override
public <T extends Object> T rPop(final String queueName) {
return redisTemplate.execute((RedisCallback<T>)connection -> {
byte[] value = connection.rPop(queueName.getBytes());
return value == null ? null : (T)unSerialize(value);
});
}

/**
* 获取队列长度
*
* @param queueName 键名称
* @return
*/
@Override
public Long lLen(final String queueName) {
return redisTemplate.execute((RedisCallback<Long>)connection -> {
Long value = connection.lLen(queueName.getBytes());
return value == null ? null : value;
});
}

@Override
/**
* 获取一个范围的数组
* @param queueName
* @param <T>
* @return
*/
public <T extends Object> T lRang(final String queueName) {
return redisTemplate.execute((RedisCallback<T>)connection -> {
List<byte[]> value = connection.lRange(queueName.getBytes(), 0L, -1L);
if (value == null) {
return null;
}
List list = new ArrayList();
for (byte[] byts : value) {
list.add(unSerialize(byts));
}
return (T)list;
});
}

/**
* 封装redis的set方法,用于专门设置一个String类型缓存
*
* @param key 键名称
* @param value 值
* @return
*/
@Override
public boolean setString(final String key, final String value) {
return redisTemplate.execute((RedisCallback<Boolean>)connection -> {
connection.set(key.getBytes(), value.getBytes());
return true;
});
}

/**
* 封装redis的set方法,用于专门设置一个String类型缓存
*
* @param key 键名称
* @param value 值
* @param timeout 超时时长
* @param timeUnit 超时时长单位
* @return
*/
@Override
public boolean setString(final String key, final String value, long timeout, TimeUnit timeUnit) {
boolean r1 = redisTemplate.execute((RedisCallback<Boolean>)connection -> {
connection.set(key.getBytes(), value.getBytes());
return true;
});
boolean r2 = setExpire(key, timeout, timeUnit);
return r1 && r2;
}

/**
* 封装redis的get方法,用于获取一个String类型缓存
*
* @param key 键名称
* @return String类型值
*/
@Override
public String getString(final String key) {
return redisTemplate.execute((RedisCallback<String>)connection -> {
byte[] value = connection.get(key.getBytes());
return value == null ? null : new String(value);
});
}

/**
* 缓存一个对象数据
*
* @param key 键名称
* @param value 对象值
* @return
*/
@Override
public <T extends Object> boolean setObject(final String key, final T value) {
return redisTemplate.execute((RedisCallback<Boolean>)connection -> {
connection.set(key.getBytes(), serialize(value));
return true;
});
}

/**
* 缓存一个对象数据
*
* @param key 键名称
* @param value 对象值
* @param timeout
* @param timeUnit
* @return
*/
@Override
public boolean setObject(final String key, final Object value, long timeout, TimeUnit timeUnit) {
boolean r1 = redisTemplate.execute((RedisCallback<Boolean>)connection -> {
connection.set(key.getBytes(), serialize(value));
return true;
});
boolean r2 = setExpire(key, timeout, timeUnit);
return r1 && r2;
}

/**
* 获取一个对象数据
*
* @param key 键名称
* @param <T> 对象类型
* @return
*/
@Override
public <T extends Object> T getObject(final String key) {
return redisTemplate.execute((RedisCallback<T>)connection -> {
byte[] value = connection.get(key.getBytes());
return value == null ? null : (T)unSerialize(value);
});
}

/**
* 删除一个redis缓存
*
* @param key
* @return
*/
@Override
public long deleteKey(final String key) {
return redisTemplate.execute((RedisCallback<Long>)connection -> connection.del(key.getBytes()));
}

/**
* 将对象转换为字节数组
*
* @param object 对象
* @return
*/
<T extends Object> byte[] serialize(T object) {
try {
//序列化
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(object);
return bao.toByteArray();
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
}

/**
* 将字节数组转换为对象
*
* @param bytes
* @return
*/
<T extends Object> T unSerialize(byte[] bytes) {
try {
//反序列化
ByteArrayInputStream bao = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bao);
return (T)ois.readObject();
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
}

/**
* 设置一个缓存的过期
*
* @param key
* @param timeout
* @param timeUnit
* @return
*/
@Override
public boolean setExpire(String key, long timeout, TimeUnit timeUnit) {
return redisTemplate.expire(key, timeout, timeUnit);
}

/**
* 设置一个根据业务进行区分的key
*
* @param value 值
* @param timeout 有效时长
* @param timeUnit 时间类型
* @param keys key 类似于biz,userId,XXXXXX 实际存入biz:userId:XXXXXX
* @return
*/
@Override
public boolean setString(String value, long timeout, TimeUnit timeUnit, String... keys) {
if (keys == null || keys.length < 1) {
return false;
}
final String key = CommonUtils.produceKey(keys);
return this.setString(key, value, timeout, timeUnit);
}

/**
* 缓存一个有超时时长的数据
*
* @param value
* @param timeout
* @param timeUnit
* @param keys key 类似于biz,userId,XXXXXX 实际存入biz:userId:XXXXXX
* @return
*/
@Override
public <T> boolean setObject(T value, long timeout, TimeUnit timeUnit, String... keys) {
if (keys == null || keys.length < 1) {
return false;
}
final String key = CommonUtils.produceKey(keys);
return this.setObject(key, value, timeout, timeUnit);
}

/**
* redis提供的setNX函数,具有互斥的性质,可以用来设置一个标记判断唯一操作,值与key想通
*
* @param key 键名称,需要唯一
* @param value 值
* @return
*/
@Override
public boolean setNX(String key, String value) {
return redisTemplate.execute(
(RedisCallback<Boolean>)connection -> connection.setNX((key).getBytes(), value.getBytes()));
}

/**
* redis提供的setNX函数,具有互斥的性质,可以用来设置一个标记判断唯一操作
*
* @param key 键名称,需要唯一
* @param value 值
* @param timeout 超时时长
* @param timeUnit 超时时长单位
* @return
*/
@Override
public boolean setNX(final String key, final String value, long timeout, TimeUnit timeUnit) {
boolean r1 = redisTemplate.execute(
(RedisCallback<Boolean>)connection -> connection.setNX((key).getBytes(), value.getBytes()));
boolean r2 = setExpire(key, timeout, timeUnit);
return r1 && r2;
}

@Override
public long getIncr(String key, long timeout, TimeUnit timeUnit) {
RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
Long increment = entityIdCounter.getAndIncrement();

//初始设置过期时间
if (null == increment || increment.longValue() == 0) {
setExpire(key, timeout, timeUnit);
}
return increment;
}

@Override
public long getIncr(String key) {
return new RedisAtomicLong(key, redisTemplate.getConnectionFactory()).getAndIncrement();
}

@Override
/**
* 获取指定key的到期时间
* @param key
* @param timeUnit
* @return
*/
public long getTTL(String key, TimeUnit timeUnit) {
return redisTemplate.getExpire(key, timeUnit);
}

@Override
/**
* 获取指定key的到期时间 默认分组
* @param key
* @return
*/
public long getTTL(String key) {
return getTTL(key, TimeUnit.SECONDS);
}

/**
* 将列表存入HASH
*
* @param orgId -机构ID
* @param redisTypeEnum -字典类型(包含散列名称,key-value中key对应的实体字段)
* @param collection -对象列表
* @return
*/
@Override
public boolean hashMultiSet(RedisTypeEnum redisTypeEnum, Collection<?> collection, Long orgId) {
String hashKey = redisTypeEnum.getHashKey();
String keyType = redisTypeEnum.getKeyType();
if (StringUtils.isBlank(hashKey) || StringUtils.isBlank(keyType) || collection == null || collection
.isEmpty()) {
return false;
}
if (!Objects.isNull(orgId)) {
hashKey = CommonUtils.produceKey(orgId + "", hashKey);
}
//指定map初始容量为集合容量
Map<String, String> map = new HashMap<>(Double.valueOf(collection.size() / 0.75 + 1).intValue());
collection.forEach(c -> {
map.put(this.getKeyTypeValue(keyType, c), JSON.toJSONString(c));
});
// 增加缓存过期时间,目前数据库清了,缓存没清,缓存就会产生脏数据。
redisTemplate.expire(hashKey, 480, TimeUnit.MINUTES);
redisTemplate.opsForHash().putAll(hashKey, map);
return true;
}

/**
* 获取多个指定对象tclass,散列为hashKey下的多个key的对象集合
*
* @param redisTypeEnum 字典类型(包含散列名称,key-value中key对应的实体字段)
* @param tClass 对象class
* @param keys key列表 can not be null && empty
* @param <T>
* @return 指定对象T的集合列表
*/
@Override
public <T> List<T> hashMultiGet(RedisTypeEnum redisTypeEnum, Class<T> tClass, List<String> keys, Long orgId) {
String hashKey = redisTypeEnum.getHashKey();
if (StringUtils.isBlank(hashKey) || Objects.isNull(tClass) || Objects.isNull(keys) || keys.size() < 1) {
return new ArrayList<>();
}
if (orgId != null) {
hashKey = CommonUtils.produceKey(orgId + "", hashKey);
}
try {
List<T> list = new ArrayList<>();
List<Object> objects = redisTemplate.opsForHash().multiGet(hashKey, Arrays.asList(keys.toArray()));
if (objects != null && !objects.isEmpty()) {
for (Object obj : objects) {
if (Objects.isNull(obj)) {
continue;
}
String text = CommonUtils.covert(obj);
T t1 = JSON.parseObject(text, tClass);
list.add(t1);
}
}
return list;
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return null;
}

/**
* 获取指定对象tclass,散列为hashKey下的key的对象
*
* @param redisTypeEnum 字典类型(包含散列名称,key-value中key对应的实体字段)
* @param tClass 对象class
* @param key key
* @return
*/
@Override
public <T> T hashGet(RedisTypeEnum redisTypeEnum, Class<T> tClass, String key, Long orgId) {
String hashKey = redisTypeEnum.getHashKey();
if (StringUtils.isBlank(hashKey) || Objects.isNull(tClass) || StringUtils.isBlank(key)) {
return null;
}
List<String> keys = new ArrayList<>();
keys.add(key);
List<T> list = this.hashMultiGet(redisTypeEnum, tClass, keys, orgId);
if (!Objects.isNull(list) && !list.isEmpty()) {
return list.get(0);
}
return null;
}

@Override
public String getSerialNumber(Long orgId, SerialNumberTypeEnum serialNumberTypeEnum,
SerialNumberMethodEnum serialNumberMethodEnum) {
if (!ObjectUtils.allNotNull(orgId, serialNumberMethodEnum, serialNumberTypeEnum)) {
return null;
}
// 生成规则:yyMMdd001 年后两位+月+日+3位递增号 每天清零
if (SerialNumberMethodEnum.SER_Method_0001.equals(serialNumberMethodEnum)) {
return serMethod001(orgId, serialNumberTypeEnum);
} else if (SerialNumberMethodEnum.SER_Method_0002.equals(serialNumberMethodEnum)) {
return serMethod002(orgId, serialNumberTypeEnum);
} else if (SerialNumberMethodEnum.SER_Method_0003.equals(serialNumberMethodEnum)) {
return serMethod003(orgId, serialNumberTypeEnum);
} else if (SerialNumberMethodEnum.SER_Method_0004.equals(serialNumberMethodEnum)) {
return serMethod004(orgId, serialNumberTypeEnum);
} else if (SerialNumberMethodEnum.SER_Method_0005.equals(serialNumberMethodEnum)) {
return serMethod005(orgId, serialNumberTypeEnum);
}
return null;
}

/**
* 生成规则:yyMMdd001 年后两位+月+日+3位递增号 每天清零
*
* @param orgId 机构ID
* @param serialNumberTypeEnum 序列号类型
* @return 序列号
*/
private String serMethod001(Long orgId, SerialNumberTypeEnum serialNumberTypeEnum) {
Date date = new Date();
// 设置失效类型(yyyyMMdd为:每天失效,yyyyMM为:每月失效,yyyy为:每年失效,不要下段代码为:永久有效)
SimpleDateFormat redisKey = new SimpleDateFormat("yyyyMMdd");
// redis上保存的KEY (将日期拼接到KEY里,保存第二天获取的是新的)
String key = "SerialNum:" + redisKey.format(date) + "_" + serialNumberTypeEnum + "_" + orgId;
// 设置过期类型(24 数量, TimeUnit 单位)此处需要与上面相对应
long serNum = getIncr(key, 24, TimeUnit.HOURS);
// reids取序号从0开始,需要加1
serNum = serNum + 1;
SimpleDateFormat sf = new SimpleDateFormat("yyMMdd");
final Long maxNum = 999L;
if (serNum > maxNum) {
return sf.format(new Date());
}
return sf.format(date) + StringUtils.leftPad(serNum + "", 3, "0");
}

/**
* 生成规则:生成规则:yyyyMMdd00001 四位年+月+日+5位递增号 每天清零
*
* @param orgId 机构ID
* @param serialNumberTypeEnum 序列号类型
* @return 序列号
*/
private String serMethod002(Long orgId, SerialNumberTypeEnum serialNumberTypeEnum) {
Date date = new Date();
// 设置失效类型(yyyyMMdd为:每天失效,yyyyMM为:每月失效,yyyy为:每年失效,不要下段代码为:永久有效)
SimpleDateFormat redisKey = new SimpleDateFormat("yyyyMMdd");
// redis上保存的KEY (将日期拼接到KEY里,保存第二天获取的是新的)
String key = "SerialNum:" + redisKey.format(date) + "_" + serialNumberTypeEnum + "_" + orgId;
// 设置过期类型(24 数量, TimeUnit 单位)此处需要与上面相对应
long serNum = getIncr(key, 24, TimeUnit.HOURS);
// reids取序号从0开始,需要加1
serNum = serNum + 1;
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
final Long maxNum = 99999L;
if (serNum > maxNum) {
return sf.format(new Date());
}
return sf.format(date) + StringUtils.leftPad(serNum + "", 5, "0");
}

/**
* 生成规则:生成规则:yyyMMdd00001 三位年+月+日+6位递增号 每天清零
*
* @param orgId 机构ID
* @param serialNumberTypeEnum 序列号类型
* @return 序列号
*/
private String serMethod003(Long orgId, SerialNumberTypeEnum serialNumberTypeEnum) {
Date date = new Date();
// 设置失效类型(yyyyMMdd为:每天失效,yyyyMM为:每月失效,yyyy为:每年失效,不要下段代码为:永久有效)
SimpleDateFormat redisKey = new SimpleDateFormat("yyyyMMdd");
// redis上保存的KEY (将日期拼接到KEY里,保存第二天获取的是新的)
String key = "SerialNum:" + redisKey.format(date) + "_" + serialNumberTypeEnum + "_" + orgId;
// 设置过期类型(24 数量, TimeUnit 单位)此处需要与上面相对应
long serNum = getIncr(key, 24, TimeUnit.HOURS);
// reids取序号从0开始,需要加1
serNum = serNum + 1;
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
final Long maxNum = 999999L;
if (serNum > maxNum) {
return sf.format(new Date()).substring(1);
}
return sf.format(date).substring(1) + StringUtils.leftPad(serNum + "", 6, "0");
}

/**
* 生成规则:9位递增号 不清零
*
* @param orgId 机构ID
* @param serialNumberTypeEnum 序列号类型
* @return 序列号
*/
private String serMethod004(Long orgId, SerialNumberTypeEnum serialNumberTypeEnum) {
// redis上保存的KEY (将日期拼接到KEY里,保存第二天获取的是新的)
String key = "SerialNum:" + "_" + serialNumberTypeEnum + "_" + orgId;
// 设置过期类型 不过期
long serNum = getIncr(key);
// reids取序号从0开始,需要加1
serNum = serNum + 1;
return StringUtils.leftPad(serNum + "", 9, "0");
}

/**
* 生成规则:省异地机构交易流水号-4位递增号 不清零
*
* @param orgId 机构ID
* @param serialNumberTypeEnum 序列号类型
* @return 序列号 30位
*/
private String serMethod005(Long orgId, SerialNumberTypeEnum serialNumberTypeEnum) {
Date date = new Date();
// 设置失效类型(yyyyMMdd为:每天失效,yyyyMM为:每月失效,yyyy为:每年失效,不要下段代码为:永久有效)
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
// redis上保存的KEY (将日期拼接到KEY里,保存第二天获取的是新的)
String key = "SerialNum:" + "_" + serialNumberTypeEnum + "_" + orgId;
// 设置过期类型(1 数量, TimeUnit 单位)此处需要与上面相对应
long serNum = getIncr(key, 1, TimeUnit.MINUTES) + 1;
String newOrgId = String.valueOf(orgId);
if (newOrgId.length() > 12) {
newOrgId = newOrgId.substring(0, 12);
} else {
newOrgId = StringUtils.rightPad(newOrgId, 12, "0");
}
return newOrgId + sf.format(date) + StringUtils.leftPad(serNum + "", 4, "0");
}

/**
* 获取指定key的值
*
* @param keyType
* @param obj
* @param <T>
* @return
*/
private <T> String getKeyTypeValue(String keyType, T obj) {
try {
Field field = obj.getClass().getDeclaredField(keyType);
field.setAccessible(true);
String type = (String)field.get(obj);
return type;
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return null;
}

@Override
/**
* 获取当前的序列号 不自增
*/
public Long getButNoIncr(String key) {
key = "SerialNum:" + "_" + key ;
return new RedisAtomicLong(key, redisTemplate.getConnectionFactory()).get();
}

@Override
/**
* 按照给定的规则返回序列号值
* @param valueFunction 处理返回值的方法
* @param keyFunction 处理key值的方法
* @param days 保存有效期 单位是天
* @return
*/
public String getSerialNumber(Function<Long,String> valueFunction, Supplier<String> keyFunction, int days){
//SerialNumberTypeEnum serialNumberTypeEnum
String key = "SerialNum:" + "_" + keyFunction.get() ;
long serNum = getIncr(key,days,TimeUnit.DAYS);
serNum = serNum + 1;
return valueFunction.apply(serNum);
}
}

```