017-学习Redis-SpringDataRedis项目操作类型、设置失效时间、整合哨兵
- 一、项目搭建
- 1、创建项目
- 2、添加配置
- 3.Lettuce和Jedis的区别
- 4、测试连接:
- 5、为什么StringRedisTemplate和RedisTemplate<>都不乱码
- 二、序列化模板(转JSON数据,并且不乱码)
- 1、三种方法序列化问题:
- 2、代码:
- 1.序列化代码:configuration
- 2.实体类:一定要imp实现序列化
- 3.user类型转为字符串,传到redis
- 4.用redisTemplate测试后:发现不在乱码了,并是json格式:
- 三、使用StringRedisTemplate手动序列化
- 如何启动项目:
- 1、开启redis服务器
- 2、开启reids的哨兵
- 3、查看info replication
- 4、查看日志tail -f /opt/redis/log/sentinel-26381.log
- 三、操作数据类型
- 1、String类型
- 2、hash类型
- 3、list类型
- 4、set类型
- 5、sortedset类型
- 四、获取所有Key+key失效时间
- 1、获取所有的key
- 2、key的失效时间
- 五、SpringDataRedis整合哨兵
- 1、第一种方法
- 2、第二种方法
一、项目搭建
1、创建项目
- 选择Spring Initializr
- NoSql-redis/ Spring Web
- 添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>sprintDataRedis-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sprintDataRedis-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--spring data redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons-pool2 对象池依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--web 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--test 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2、添加配置
spring:
redis:
# Redis服务器地址
host: 192.168.0.121
# Redis服务器端口
port: 6381
# Redis服务器端口
password: root
# Redis服务器端口
database: 0
# 连接超时时间
timeout: 10000ms
lettuce:
pool:
# 最大连接数,默认8
max-active: 1024
# 最大连接阻塞等待时间,单位毫秒,默认-1ms
max-wait: 10000ms
# 最大空闲连接,默认8
max-idle: 200
# 最小空闲连接,默认0
min-idle: 5
3.Lettuce和Jedis的区别
Jedis 是一个优秀的基于 Java 语言的 Redis 客户端,但是,其不足也很明显: Jedis 在实现上是直接连接 RedisServer,在多个线程间共享一个 Jedis 实例时是线程不安全的,如果想要在多线程场景下使用 Jedis ,需要使用连接池,每个线程都使用自己的 Jedis 实例,当连接数量增多时,会消耗较多的物理资源。
Lettuce 则完全克服了其线程不安全的缺点: Lettuce 是基于 Netty 的连接(StatefulRedisConnection),Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel,集群,流水线,自动重新连接和 Redis 数据模型。
4、测试连接:
@SpringBootTest
public class SprintDataRedisDemoApplicationTests {
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void testRedisTemplate(){
ValueOperations<String, String> rt = redisTemplate.opsForValue();
rt.set("rt","testRT");
String rt1 = rt.get("rt");
System.out.println(rt1);
}
@Test
public void testStringRedisTemplate() {
ValueOperations<String, String> srt = stringRedisTemplate.opsForValue();
//添加一条String类型数据,key=ops,value=test
srt.set("srt","testSrt");
String ops1 = srt.get("ops");
System.out.println(ops1);
}
}
5、为什么StringRedisTemplate和RedisTemplate<>都不乱码
StringRedisTemplate 继承了 RedisTemplate<String,string>
- ReidsTemplate 存入后乱码
- RedisTemplate<>he StringRedisTemplate不乱码
- ReidsTemplate 存入后乱码
- RedisTemplate<>he StringRedisTemplate不乱码
二、序列化模板(转JSON数据,并且不乱码)
- 默认情况下的模板 RedisTemplate<Object, Object>,默认序列化使用的是JdkSerializationRedisSerializer ,存储二进制字节码。这时需要自定义模板,当自定义模板后又想存储String 字符串时,可以使StringRedisTemplate的方式,他们俩并不冲突。
1、三种方法序列化问题:
- 自定义模板解决序列化问题
序列化问题:
要把 domain object 做为 key-value 对保存在 redis 中,就必须要解决对象的序列化问题。Spring Data Redis给我们
提供了一些现成的方案:
- JdkSerializationRedisSerializer 使用JDK提供的序列化功能。 优点是反序列化时不需要提供类型信息(class),但缺点是序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗 Redis 服务器的大量内存。
- Jackson2JsonRedisSerializer 使用 Jackson 库将对象序列化为JSON字符串。优点是速度快,序列化后的字符串
短小精悍。但缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。通过查看源代码,发现其只在反序列化过程中用到了类型信息。 - GenericJackson2JsonRedisSerializer 通用型序列化,这种序列化方式不用自己手动指定对象的 Class
2、代码:
1.序列化代码:configuration
Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory
redisConnectionFactory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
//为string类型key设置序列器
redisTemplate.setKeySerializer(new StringRedisSerializer());
//为string类型value设置序列器
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//为hash类型key设置序列器
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//为hash类型value设置序列器
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
序列化方式二:
2.实体类:一定要imp实现序列化
3.user类型转为字符串,传到redis
Test:
/**
* 测试序列化
* 将user类型,转为字符串传到redis
*/
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testSerial(){
User user = new User();
user.setId(1);
user.setUsername("张三");
user.setPassword("111");
ValueOperations<String, Object> value = redisTemplate.opsForValue();
value.set("userInfo",user);
System.out.println(value.get("userInfo"));
}
4.用redisTemplate测试后:发现不在乱码了,并是json格式:
三、使用StringRedisTemplate手动序列化
如何启动项目:
1、开启redis服务器
2、开启reids的哨兵
./redis-sentinel /opt/redis/conf/sentinel-26379.conf
3、查看info replication
4、查看日志tail -f /opt/redis/log/sentinel-26381.log
三、操作数据类型
1、String类型
//测试String类型
@Test
public void testString(){
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("setTest","test");
//读取数据
String name = (String) valueOperations.get("setTest");
System.out.println(name);
//添加层级目录:
valueOperations.set("user:01","lisi");
//添加多条数据
Map<String,String> hashMap = new HashMap();
hashMap.put("map01","value01");
hashMap.put("map02","value02");
valueOperations.multiSet(hashMap);
//获取多条数据\
List<String> keys= new ArrayList<>();
keys.add("setTest");
keys.add("map01");
keys.add("map02");
List list = valueOperations.multiGet(keys);
list.forEach(System.out::println);
//通用的删除方法
redisTemplate.delete("map01");
}
2、hash类型
//测试hash类型
@Test
public void testHash(){
HashOperations hashOperations = redisTemplate.opsForHash();
/**
* 添加一条数据,
* 第一个参数是 Redis的key
* 第二个参数是 hash的key
* 第三个参数是 hash的value
*/
hashOperations.put("users","name","zhangsanHash");
//添加多条数据
Map<String,String> map = new HashMap<>();
map.put("age","12");
map.put("address","beijing");
hashOperations.putAll("users",map);
//获取多条数据
List<String> list = new ArrayList<>();
list.add("name");
list.add("age");
list.add("address");
//通过key,来获取对应的value
List users = hashOperations.multiGet("users", list);
users.forEach(System.out::println);
//获取map的所有的数据类型
Map<String,String> entries = hashOperations.entries("users");
entries.entrySet().forEach(e->{
System.out.println(e.getKey()+"---->"+e.getValue());
});
}
3、list类型
// 3.操作list
@Test
public void testList() {
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
// 左添加(上)
// listOperations.leftPush("students", "Wang Wu");
// listOperations.leftPush("students", "Li Si");
// 左添加(上) 把value值放到key对应列表中pivot值的左面,如果pivot值存在的话
//listOperations.leftPush("students", "Wang Wu", "Li Si");
// 右添加(下)
// listOperations.rightPush("students", "Zhao Liu");
// 获取 start起始下标 end结束下标 包含关系
List<Object> students = listOperations.range("students", 0,2);
for (Object stu : students) {
System.out.println(stu);
}
// 根据下标获取
Object stu = listOperations.index("students", 1);
System.out.println(stu);
// 获取总条数
Long total = listOperations.size("students");
System.out.println("总条数:" + total);
// 删除单条 删除列表中存储的列表中几个出现的Li Si。
listOperations.remove("students", 1, "Li Si");
// 删除多条
redisTemplate.delete("students");
}
4、set类型
// 4.操作set-无序
@Test
public void testSet() {
SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
// 添加数据
String[] letters = new String[]{"aaa", "bbb", "ccc", "ddd", "eee"};
//setOperations.add("letters", "aaa", "bbb", "ccc", "ddd", "eee");
setOperations.add("letters", letters);
// 获取数据
Set<Object> let = setOperations.members("letters");
for (Object letter: let) {
System.out.println(letter);
}
// 删除
setOperations.remove("letters", "aaa", "bbb");
}
5、sortedset类型
// 5.操作sorted set-有序
@Test
public void testSortedSet() {
ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
ZSetOperations.TypedTuple<Object> objectTypedTuple1 =
new DefaultTypedTuple<Object>("zhangsan", 7D);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 =
new DefaultTypedTuple<Object>("lisi", 3D);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 =
new DefaultTypedTuple<Object>("wangwu", 5D);
ZSetOperations.TypedTuple<Object> objectTypedTuple4 =
new DefaultTypedTuple<Object>("zhaoliu", 6D);
ZSetOperations.TypedTuple<Object> objectTypedTuple5 =
new DefaultTypedTuple<Object>("tianqi", 2D);
Set<ZSetOperations.TypedTuple<Object>> tuples = new
HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
tuples.add(objectTypedTuple4);
tuples.add(objectTypedTuple5);
// 添加数据
zSetOperations.add("score", tuples);
// 获取数据
Set<Object> scores = zSetOperations.range("score", 0, 4);
for (Object score: scores) {
System.out.println(score);
}
// 获取总条数
Long total = zSetOperations.size("score");
System.out.println("总条数:" + total);
// 删除
zSetOperations.remove("score", "zhangsan", "lisi");
}
四、获取所有Key+key失效时间
1、获取所有的key
// 测试获取有的key的数量
@Test
public void testKey(){
Set keys = redisTemplate.keys("*");
keys.forEach(System.out::println);
}
2、key的失效时间
//测试失效时间:
@Test
public void testExpire(){
//第一种设置失效时间
ValueOperations valueOperations = redisTemplate.opsForValue();
//valueOperations.set("testCode","test",20, TimeUnit.SECONDS);
//第二种, 给以及存在的key设置失效的时间:
redisTemplate.expire("users",20, TimeUnit.SECONDS);
/*//查看失效的时间
Long testCode = redisTemplate.getExpire("testCode");
System.out.println(testCode);*/
}
五、SpringDataRedis整合哨兵
上个文章搭建了主从服用、主备切换,用哨兵去监控master节点。那么SpringDateRedis也可以整合哨兵。letts才支持。
1、第一种方法
#哨兵模式
sentinel:
#主节点名称
master: mymaster
#节点
nodes: 192.168.0.121:26379,192.168.0.121:26380,192.168.0.121:26381
2、第二种方法
conf/RedisConfig
//加入哨兵bean
@Bean
public RedisSentinelConfiguration redisSentinelConfiguration(){
RedisSentinelConfiguration rsc = new RedisSentinelConfiguration()
.master("mymaster")
.sentinel("192.168.0.121",26379)
.sentinel("192.168.0.121",26380)
.sentinel("192.168.0.121",26381);
//设置登录密码
rsc.setPassword("root");
return rsc;
}