继上一篇创建测试基类之后,可以根据父类创建子类进行专门的测试,下面将针对基于jedis连接redis cluster集群的操作做一个系列文章。本章内容讲解redis 字符串数据结构的一些jedis操作。
package com.coderman.jedis.clusterdemo;
import com.alibaba.fastjson.JSON;
import com.coderman.jedis.dto.PersonDto;
import com.coderman.jedis.serialize.ProtoStuffSerializerUtil;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* @Author fanchunshuai
* @Date 2019/12/28 18
* @Description:Redis的String数据结构练习
*
* 字符串类型的值实际可以 是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、
* 数字 (整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能 超过512MB。
*
*字符串类型的内部编码有3种:
* ·int:8个字节的长整型。
* ·embstr:小于等于39个字节的字符串。
* ·raw:大于39个字节的字符串。
* Redis会根据当前值的类型和长度决定使用哪种内部编码实现。
* Redis没有采用原生C语言的字符串类型而是自己实现了字符串结构,内 部简单动态字符串(simple dynamic string,SDS)。
*
*
* Redis自身实现的字符串结构有如下特点:
* ·O(1)时间复杂度获取:字符串长度、已用长度、未用长度。
* ·可用于保存字节数组,支持安全的二进制数据存储。
* ·内部实现空间预分配机制,降低内存再分配次数。
* ·惰性删除机制,字符串缩减后的空间不释放,作为预分配空间保留。
*
* https://mp.weixin.qq.com/s/3IptChwLLMN6aTeQhapSNw
*
*/
public class StringDataAPITest extends ClusterTest {
private static final String USER_PREFIX = "sso:user:";
@Test
public void testAddStr(){
String userId = USER_PREFIX+1;
cluster.set(userId,"樊春帅");
String userName = cluster.get(userId);
System.out.println("userName = "+userName);
}
/**
* 修改
*/
@Test
public void testUpdateStr(){
String userId = USER_PREFIX+2;
cluster.set(userId,"樊春帅222","NX","EX",30);
String userName = cluster.get(userId);
System.out.println("userName = "+userName);
}
/**
* json序列化
* @throws InterruptedException
*/
@Test
public void testAddPersonDto() throws InterruptedException {
PersonDto personDto = new PersonDto();
personDto.setAge(27);
personDto.setId(3L);
personDto.setCard("asdfnalsnl23");
personDto.setName("fanchunshuai");
String userKey = USER_PREFIX+"3";
//1.json序列化,返回值是OK,设置过期时间30s
//nx:当键不存在时添加成功,否则失败可以用于实现分布式锁
//ex:过期时间
String value = cluster.set(userKey, JSON.toJSONString(personDto),"NX","EX",30);
System.out.println("value = "+value);
//查询
String strPerson = cluster.get(userKey);
System.out.println("strPerson = "+strPerson);
//反序列化
PersonDto personDto1 = JSON.parseObject(strPerson,PersonDto.class);
System.out.println(JSON.toJSONString(personDto1));
//更新过期时间,为2秒
cluster.expire(userKey,2);
Thread.sleep(2000);
//再次获取
String personExpireed = cluster.get(userKey);
System.out.println("personExpireed = "+personExpireed);
//xx:当键存在时更新成功,否则失败
//ex:过期时间
String valuex = cluster.set(userKey, JSON.toJSONString(personDto),"xx","EX",30);
}
/**
* 更新
* @throws InterruptedException
*/
@Test
public void testUpdatePersonDto() throws InterruptedException {
PersonDto personDto = new PersonDto();
personDto.setAge(27);
personDto.setId(4L);
personDto.setCard("asdkfasldfnkalsdfnals");
personDto.setName("zhangsan");
String userKey = USER_PREFIX+"4";
//1.json序列化,返回值是OK,设置过期时间30s
String value = cluster.set(userKey, JSON.toJSONString(personDto),"NX","EX",30);
System.out.println("value = "+value);
//2.覆盖
cluster.set(userKey, "");
String newValue = cluster.get(userKey);
System.out.println("newValue = "+newValue);
}
/**
* protobuff序列化与反序列化
* @throws InterruptedException
*/
@Test
public void testPersonDtoProtoBuff() throws InterruptedException {
PersonDto personDto = new PersonDto();
personDto.setAge(27);
personDto.setId(5L);
personDto.setCard("asdkfasldfnkalsdfnals");
personDto.setName("zhangsan");
String userKey = USER_PREFIX+"5";
//1.protoStuff序列化,返回值是OK,设置过期时间30s
String value = cluster.set(userKey.getBytes(), ProtoStuffSerializerUtil.serialize(personDto),"NX".getBytes(),"EX".getBytes(),30);
System.out.println("value = "+value);
byte[] newValue = cluster.get(userKey.getBytes());
System.out.println("newValue = "+ProtoStuffSerializerUtil.deserialize(newValue,PersonDto.class));
String newKey = userKey+"1000";
//集群模式下不支持该命令,会报错
// No way to dispatch this command to Redis Cluster because keys have different slots.
Long id = cluster.renamenx(userKey,newKey);
System.out.println("id = "+id);
}
/**
* 测试批量获取
*/
@Test
public void testMget(){
List<String> stringList = new ArrayList<>();
for (int i = 10; i < 1000 ; i++) {
String key = USER_PREFIX +i;
cluster.set(key,key);
stringList.add(key);
}
String[] strings = new String[stringList.size()];
stringList.toArray(strings);
//集群模式不支持该api,会报错
//No way to dispatch this command to Redis Cluster because keys have different slots.
List<String> values = cluster.mget(strings);
values.forEach(str->{
System.out.println(str);
});
}
}
涉及到protobuff的序列化,这里引入maven坐标:
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.5.9</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.5.9</version>
</dependency>
提供protobuff的工具类:
package com.coderman.jedis.serialize;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
/**
* @Author fanchunshuai
* @Date 2019/12/28 18
* @Description:
*/
public class ProtoStuffSerializerUtil {
private ProtoStuffSerializerUtil() {
}
/**
* 序列化单个对象
* @param obj
* @param <T>
* @return
*/
public static <T> byte[] serialize(T obj){
if (null == obj) {
throw new RuntimeException("序列化对象不能为空:" + obj);
}
Schema<T> schema = (Schema<T>) RuntimeSchema.getSchema(obj.getClass());
LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
byte[] protostuff = null;
try {
protostuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
throw new RuntimeException("序列化->" + obj.getClass() + "对象" + obj + "发生异常", e);
} finally {
buffer.clear();
}
return protostuff;
}
/**
* 反序列化单个对象
* @param paramArrayOfByte
* @param targetClass
* @param <T>
* @return
*/
public static <T> T deserialize(byte[] paramArrayOfByte, Class<T> targetClass) {
if (null == paramArrayOfByte || paramArrayOfByte.length == 0) {
throw new RuntimeException("反序列化对象发生异常,byte序列为空");
}
T instance = null;
try {
instance = targetClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("反序列化过程中一句类型创建对象失败", e);
}
Schema<T> schema = RuntimeSchema.getSchema(targetClass);
ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
return instance;
}
/**
* 序列化对象集合(List)
* @param objList
* @param <T>
* @return
*/
public static <T> byte[] serializeList(List<T> objList) {
if (null == objList || objList.isEmpty()) {
throw new RuntimeException("序列化对象列表" + objList + "参数异常");
}
Schema<T> schema = (Schema<T>) RuntimeSchema.getSchema(objList.get(0).getClass());
LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
byte[] protostuff = null;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer);
protostuff = bos.toByteArray();
} catch (Exception e) {
throw new RuntimeException("序列化对象列表" + objList + "发生异常", e);
} finally {
buffer.clear();
}
return protostuff;
}
/**
* 反序列化对象集合(List)
* @param <T>
* @param paramArrayOfByte
* @param targetClass
* @return
*/
public static <T> List<T> deserializeList(byte[] paramArrayOfByte, Class targetClass) {
if (null == paramArrayOfByte || paramArrayOfByte.length == 0) {
throw new RuntimeException("反序列化对象发生异常,byte序列为空");
}
Schema<T> schema = RuntimeSchema.getSchema((Class<T>) targetClass);
List<T> result = null;
try {
result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(paramArrayOfByte), schema);
} catch (IOException e) {
throw new RuntimeException("反序列化对象列表发生异常", e);
}
return result;
}
}