目录
讲解一:简介
讲解二:Jedis
Github
一、创建项目、
二、添加依赖
三、配置文件
四、Java连接Redis
五、通过Redis连接池获取连接对象并操作服务器
六、封装JedisUtil对外提供连接对象获取方法
七、Java操作Redis五种数据类型
1. 连接与释放
2. Jedis操作string数据类型
3. Jedis操作hash类型
4. Jedis操作list类型
5. Jedis操作set类型
6. Jedis操作sortedset数据类型
八、层级目录+失效时间
九、获取所有key&事务&删除
十、Jedis操作byte数组
讲解三:SpringDataRedis
一、简介
二、创建项目
三、添加依赖
四、添加application.yml配置文件
五、Lettuce和Jedis的区别
六、测试环境测试环境是否搭建成功
七、SpringDataRedis序列化模板
1. 序列化问题
2. 序列化解决方案
3. 自定义序列化
4. StringRedisTemplate
八、SpringData操作Redis
1. 操作string数据类型
2. 操作hash数据类型
3. 操作list数据类型
4. 操作set数据类型
5. 操作sortedset数据类型
6. 获取所有key+设置key失效时间
获取所有key&删除
设置key的失效时间
7. 通用操作
九、SpringDataRedis整合哨兵
application.yml
Bean注解配置
十、知识小结
讲解一:简介
在Redis官网中提供了各种语言的客户端,
官网地址:Connect with Redis clients | Docs
操作Redis 的 Java 客户端很多,官方推荐的有三种:
- Jedis
- Lettuce
- Redisson
标记为的就是推荐使用的java客户端,包括:
- Jedis和Lettuce:这两个主要是提供了Redis命令对应的API,方便我们操作Redis,而Spring 对 Redis 客户
端进行了整合,提供了 Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即 spring-
boot-starter-data-redis。
- Redisson:是在Redis基础上实现了分布式的可伸缩的java数据结构,例如:Map、Queue等,而且支持跨
进程的同步机制:Lock、Semaphore等待,比较适合用来实现特殊的功能需求。
讲解二:Jedis
Github
Jedis 是 Redis 的 Java 版本的客户端实现。
Jedis的官网地址: https://github.com/redis/jedis
一、创建项目、
自己创建一个Maven项目
二、添加依赖
<?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.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xxxx</groupId>
<artifactId>redis-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--
1.x 的版本默认采用的连接池技术是 Jedis,
2.0 以上版本默认连接池是 Lettuce,
如果采用 Jedis,需要排除 Lettuce 的依赖。
-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- jedis 依赖 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</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>
三、配置文件
spring:
redis:
# Redis服务器地址
host: 192.168.10.100
# Redis服务器端口
port: 6379
# Redis服务器密码
password: root
# 选择哪个库,默认0库
database: 0
# 连接超时时间
timeout: 10000ms
jedis:
pool:
# 最大连接数,默认8
max-active: 1024
# 最大连接阻塞等待时间,单位毫秒,默认-1ms
max-wait: 10000ms
# 最大空闲连接,默认8
max-idle: 200
# 最小空闲连接,默认0
min-idle: 5
四、Java连接Redis
/**
* 连接Redis
*/
@Test
public void initConn01() {
// 创建jedis对象,连接redis服务
Jedis jedis = new Jedis("192.168.10.100", 6379);
// 设置认证密码
jedis.auth("root");
// 指定数据库 默认是0
jedis.select(1);
// 使用ping命令,测试连接是否成功
String result = jedis.ping();
System.out.println(result);// 返回PONG
// 添加一条数据
jedis.set("username", "zhangsan");
// 获取一条数据
String username = jedis.get("username");
System.out.println(username);
// 释放资源
if (jedis != null)
jedis.close();
}
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,
因此我们推荐大家使用Jedis连接池代替Jedis的直连方式
package com.project.jedis.util;
import redis.clients.jedis.*;
public class JedisConnectionFactory {
private static JedisPool jedisPool;
static {
// 配置连接池
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(8);
poolConfig.setMaxIdle(8);
poolConfig.setMinIdle(0);
poolConfig.setMaxWaitMillis(1000);
// 创建连接池对象,参数:连接池配置、服务端ip、服务端端口、超时时间、密码
jedisPool = new JedisPool(poolConfig, "192.168.150.101", 6379, 1000, "123321");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
五、通过Redis连接池获取连接对象并操作服务器
/**
* 通过Redis连接池获取连接对象
*/
@Test
public void initConn02() {
// 初始化redis客户端连接池
JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), "192.168.10.100", 6379, 10000, "root");
// 从连接池获取连接
Jedis jedis = jedisPool.getResource();
// 指定数据库 默认是0
jedis.select(2);
// 使用ping命令,测试连接是否成功
String result = jedis.ping();
System.out.println(result);// 返回PONG
// 添加一条数据
jedis.set("username", "zhangsan");
// 获取一条数据
String username = jedis.get("username");
System.out.println(username);
// 释放资源
if (jedis != null)
jedis.close();
}
六、封装JedisUtil对外提供连接对象获取方法
@Configuration
public class RedisConfig {
//服务器地址
@Value("${spring.redis.host}")
private String host;
//端口
@Value("${spring.redis.port}")
private int port;
//密码
@Value("${spring.redis.password}")
private String password;
//超时时间
@Value("${spring.redis.timeout}")
private String timeout;
//最大连接数
@Value("${spring.redis.jedis.pool.max-active}")
private int maxTotal;
//最大连接阻塞等待时间
@Value("${spring.redis.jedis.pool.max-wait}")
private String maxWaitMillis;
//最大空闲连接
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
//最小空闲连接
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Bean
public JedisPool redisPoolFactory(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//注意值的转变
jedisPoolConfig.setMaxWaitMillis
(Long.parseLong(maxWaitMillis.substring(0,maxWaitMillis.length()-2)));
//注意属性名
jedisPoolConfig.setMaxTotal(maxTotal);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port,
Integer.parseInt(timeout.substring(0,timeout.length() - 2)), password);
return jedisPool;
}
}
七、Java操作Redis五种数据类型
1. 连接与释放
@Autowired
private JedisPool jedisPool;
private Jedis jedis = null;
//初始化jedis对象实例
@Before
public void initConn(){
jedis = jedisPool.getResource();
}
//释放资源
@After
public void closeConn(){
if (jedis!=null){
jedis.close();
}
}
2. Jedis操作string数据类型
// 1.操作String
@Test
public void testString() {
// 添加一条数据
jedis.set("username", "zhangsan");
jedis.set("age", "18");
// 添加多条数据 参数奇数为key 参数偶数为value
jedis.mset("address", "bj", "sex", "1");
// 获取一条数据
String username = jedis.get("username");
System.out.println(username);
// 获取多条数据
List<String> list = jedis.mget("username", "age", "address", "sex");
for (String str : list) {
System.out.println(str);
}
// 删除
//jedis.del("username");
}
3. Jedis操作hash类型
// 2.操作Hash
@Test
public void testHash() {
/*
* 添加一条数据
* 参数一:redis的key
* 参数二:hash的key
* 参数三:hash的value
*/
jedis.hset("userInfo", "name", "lisi");
// 添加多条数据
Map<String, String> map = new HashMap<>();
map.put("age", "20");
map.put("sex", "1");
jedis.hmset("userInfo", map);
// 获取一条数据
String name = jedis.hget("userInfo", "name");
System.out.println(name);
// 获取多条数据
List<String> list = jedis.hmget("userInfo", "age", "sex");
for (String str : list) {
System.out.println(str);
}
// 获取Hash类型所有的数据
Map<String, String> userMap = jedis.hgetAll("userInfo");
for (Entry<String, String> userInfo : userMap.entrySet()) {
System.out.println(userInfo.getKey() + "--" + userInfo.getValue());
}
// 删除 用于删除hash类型数据
//jedis.hdel("userInfo", "name");
}
4. Jedis操作list类型
// 3.操作list
@Test
public void testList() {
// 左添加(上)
// jedis.lpush("students", "Wang Wu", "Li Si");
// 右添加(下)
//jedis.rpush("students", "Zhao Liu");
// 获取start起始下标 end结束下标 包含关系
List<String> students = jedis.lrange("students", 0, 2);
for (String stu : students) {
System.out.println(stu);
}
// 获取总条数
Long total = jedis.llen("students");
System.out.println("总条数:" + total);
// 删除单条 删除列表中第一次出现的Li Si
// jedis.lrem("students", 1, "Li Si");
// 删除多条
// jedis.del("students");
}
5. Jedis操作set类型
/**
* 操作set
*/
@Test
public void testSet(){
//添加数据
jedis.sadd("letters","aaa","bbb","ccc","ddd","eee");
//获取数据
Set<String> set = jedis.smembers("letters");
set.forEach(System.out::println);
//获取总条数
Long total = jedis.scard("letters");
System.out.println(total);
//删除数据
jedis.srem("letters","aaa","bbb");
}
6. Jedis操作sortedset数据类型
/**
* 操作sorted set
*/
@Test
public void testSortedSet(){
//添加数据
Map<String,Double> map = new HashMap<>();
map.put("zhangsan",7D);
map.put("lisi",3D);
map.put("wangwu",5D);
map.put("zhaoliu",6D);
map.put("tianqi",1D);
jedis.zadd("score",map);
/**
* 获取数据
* 第一个参数:redis的key
* 第二个参数:起始下标
* 第三个参数:结束下标
*/
Set<String> set = jedis.zrange("score", 0, 4);
set.forEach(System.out::println);
//获取总条数
Long total = jedis.zcard("score");
System.out.println(total);
//删除数据
jedis.zrem("score","zhangsan","wangwu");
}
八、层级目录+失效时间
Redis中以层级关系、目录形式存储数据
/**
* 层级目录形式存储数据
*/
@Test
public void testDir(){
jedis.set("cart:user01:item01","apple");
System.out.println(jedis.get("cart:user01:item01"));
}
设置key的失效时间
Redis 有四个不同的命令可以用于设置键的生存时间(键可以存在多久)或过期时间(键什么时候会被删除) :
EXPlRE :用于将键 key 的生存时间设置为 ttl 秒。
PEXPIRE :用于将键 key 的生存时间设置为 ttl 毫秒。
EXPIREAT < timestamp>:用于将键 key 的过期时间设置为 timestamp 所指定的秒数时间戳。
PEXPIREAT < timestamp >:用于将键 key 的过期时间设置为 timestamp 所指定的毫秒数时间戳。
TTL:获取的值为-1说明此 key 没有设置有效期,当值为-2时证明过了有效期。
/**
* key的失效时间
*/
@Test
public void testExpire(){
//给已经存在key设置失效时间
// jedis.set("code","test");
//设置失效时间,单位秒
// jedis.expire("code",30);
//设置失效时间,单位毫秒
// jedis.pexpire("code",30000);
//查看失效时间,单位秒。-1为不失效,-2为已失效
// Long ttl = jedis.ttl("code");
// System.out.println(ttl);
//添加key的时候设置失效时间
//设置失效时间,单位秒
// jedis.setex("code",30,"test");
//设置失效时间,单位毫秒
// jedis.psetex("code",30000,"test");
//查看失效时间,单位毫秒
// Long pttl = jedis.pttl("code");
// System.out.println(pttl);
//nx,xx的用法
SetParams setParams = new SetParams();
//不存在的时候才能设置成功
// setParams.nx();
// 存在的时候才能设置成功
setParams.xx();
//设置失效时间,单位秒
// setParams.ex(30);
//查看失效时间,单位毫秒
setParams.px(30000);
jedis.set("code","test",setParams);
}
九、获取所有key&事务&删除
/**
* 查询所有key
*/
@Test
public void testAllKey(){
//当前数据库key的数量
Long size = jedis.dbSize();
System.out.println(size);
//查询当前数据库的所有key
Set<String> set = jedis.keys("*");
set.forEach(System.out::println);
}
/**
* 事务
*/
@Test
public void testMulti(){
//开启事务
Transaction tx = jedis.multi();
tx.set("tel","10086");
//提交事务
tx.exec();
//回滚事务
// tx.discard();
}
十、Jedis操作byte数组
操作byte
SerializeUtil.java
package com.xxxx.redisdemo.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* 序列化工具类
*/
public class SerializeUtil {
/**
* 将java对象转换为byte数组 序列化过程
*/
public static byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将byte数组转换为java对象 反序列化
*/
public static Object unserialize(byte[] bytes) {
if(bytes == null)return null;
ByteArrayInputStream bais = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
User.java
package com.xxxx.redisdemo.pojo;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 9148937431079191022L;
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
JedisTest.java
/**
* 操作byte数组
*/
@Test
public void testByte(){
User user = new User();
user.setId(2);
user.setUsername("zhangsan");
user.setPassword("123456");
//序列化为byte数组
byte[] userKey = SerializeUtil.serialize("user:" + user.getId());
byte[] userValue = SerializeUtil.serialize(user);
//存入redis
jedis.set(userKey,userValue);
//取出数据
byte[] bytes = jedis.get(userKey);
//反序列化
User user1 = (User) SerializeUtil.unserialize(bytes);
System.out.println(user1);
}
讲解三:SpringDataRedis
一、简介
Spring Data Redis是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,
对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
官网地址:Spring Data Redis
maven坐标:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.4.8</version>
</dependency>
SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单。
Spring Boot提供了对应的Starter,maven坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Spring Data Redis中提供了一个高度封装的类:RedisTemplate,
针对 Jedis 客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
- ValueOperations:简单K-V操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对hash类型的数据操作
- ListOperations:针对list类型的数据操作
二、创建项目
自行创建一个 SpringBoot 项目
三、添加依赖
<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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
四、添加application.yml配置文件
spring:
redis: #redis配置
# Redis服务器地址
host: 192.168.136.160
# Redis服务器端口
port: 6379
# Redis服务器密码
password: root
# Redis服务器0号数据库
database: 0
# 连接超时时间
timeout: 10000ms
lettuce:
pool:
# 最大连接数,默认8
max-active: 1024
# 最大连接阻塞等待时间,单位毫秒,默认-1ms
max-wait: 10000ms
# 最大空闲连接,默认8
max-idle: 200
# 最小空闲连接,默认0
min-idle: 5
五、Lettuce和Jedis的区别
Jedis 是一个优秀的基于 Java 语言的 Redis 客户端,但是,其不足也很明显:
Jedis 在实现上是直接连接 RedisServer,在多个线程间共享一个 Jedis 实例时是线程不安全的,
如果想要在多线程场景下使用 Jedis ,需要使用连接池,每个线程都使用自己的 Jedis 实例,
当连接数量增多时,会消耗较多的物理资源。
Lettuce 则完全克服了其线程不安全的缺点: Lettuce 是基于 Netty 的连接(StatefulRedisConnection),
Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。
多个线程可以共享一个连接 实例,而不必担心多线程并发问题。
它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel,集 群,流水线,自动重新连接和
Redis 数据模型。
六、测试环境测试环境是否搭建成功
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringDataRedisApplication.class)
public class SpringDataRedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void initconn() {
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
ops.set("username","lisi");
ValueOperations<String, String> value = redisTemplate.opsForValue();
value.set("name","wangwu");
System.out.println(ops.get("name"));
}
}
七、SpringDataRedis序列化模板
1. 序列化问题
默认情况下的模板 RedisTemplate,
默认序列化使用的是JdkSerializationRedisSerializer,存储二进制字节码。
这时需要自定义模板,当自定义模板后又想存储 String 字符串时,可以使StringRedisTemplate的方式,他们俩
并不冲突。
要把 domain object 做为 key-value 对保存在 redis 中,就必须要解决对象的序列化问题。
Spring Data Redis给我们 提供了一些现成的方案:
2. 序列化解决方案
1. JdkSerializationRedisSerializer使用JDK提供的序列化功能。
优点:是反序列化时不需要提供类型信息(class),
但缺点是序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗 Redis 服务器的大量内存。
2. Jackson2JsonRedisSerializer 使用 Jackson 库将对象序列化为JSON字符串
优点:是速度快,序列化后的字符串短小精悍。
缺点:也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。
通过查看源代码,发现其只在反序列化过程中用到了类型信息。
3. GenericJackson2JsonRedisSerializer通用型序列化,这种序列化方式不用自己手动指定对象的 Class
@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;
}
}
//序列化
@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"));
}
3. 自定义序列化
RedisTemplate可以接收任意Object作为值写入Redis:
只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:
缺点:
- 可读性差
- 内存占用较大
我们可以自定义RedisTemplate的序列化方式,代码如下:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
// 创建RedisTemplate对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置连接工厂
template.setConnectionFactory(connectionFactory);
// 创建JSON序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer =
new GenericJackson2JsonRedisSerializer();
// 设置Key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// 设置Value的序列化
template.setValueSerializer(jsonRedisSerializer);
template.setHashValueSerializer(jsonRedisSerializer);
// 返回
return template;
}
}
这里采用了JSON序列化来代替默认的JDK序列化方式。最终结果如图:
整体可读性有了很大提升,并且能将Java对象自动的序列化为JSON字符串,
并且查询时能自动把JSON反序列化为Java对象。
不过,其中记录了序列化时对应的class名称,目的是为了查询时实现自动反序列化。
这会带来额外的内存开销。
4. StringRedisTemplate
为了节省内存空间,我们可以不使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储
String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。
因为存入和读取时的序列化及反序列化都是我们自己实现的,SpringDataRedis就不会将class信息写入Redis了。
这种用法比较普遍,因此SpringDataRedis就提供了RedisTemplate的子类:StringRedisTemplate,
它的key和value的序列化方式默认就是String方式。
省去了我们自定义RedisTemplate的序列化方式的步骤,而是直接使用:
@Autowired
private StringRedisTemplate stringRedisTemplate;
// JSON序列化工具
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testSaveUser() throws JsonProcessingException {
// 创建对象
User user = new User("虎哥", 21);
// 手动序列化
String json = mapper.writeValueAsString(user);
// 写入数据
stringRedisTemplate.opsForValue().set("user:200", json);
// 获取数据
String jsonUser = stringRedisTemplate.opsForValue().get("user:200");
// 手动反序列化
User user1 = mapper.readValue(jsonUser, User.class);
System.out.println("user1 = " + user1);
}
八、SpringData操作Redis
1. 操作string数据类型
// 1.操作String
@Test
public void testString() {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
// 添加一条数据
valueOperations.set("username", "zhangsan");
valueOperations.set("age", "18");
//redis中以层级关系、目录形式存储数据
valueOperations.set("user:01", "lisi");
valueOperations.set("user:02", "wangwu");
// 添加多条数据
Map<String, String> userMap = new HashMap<>();
userMap.put("address", "bj");
userMap.put("sex", "1");
valueOperations.multiSet(userMap);
// 获取一条数据
Object username = valueOperations.get("username");
System.out.println(username);
// 获取多条数据
List<String> keys = new ArrayList<>();
keys.add("username");
keys.add("age");
keys.add("address");
keys.add("sex");
List<Object> resultList = valueOperations.multiGet(keys);
for (Object str : resultList) {
System.out.println(str);
}
// 删除
redisTemplate.delete("username");
}
2. 操作hash数据类型
// 2.操作Hash
@Test
public void testHash() {
HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
/*
* 添加一条数据
* 参数一:redis的key
* 参数二:hash的key
* 参数三:hash的value
*/
hashOperations.put("userInfo","name","lisi");
// 添加多条数据
Map<String, String> map = new HashMap();
map.put("age", "20");
map.put("sex", "1");
hashOperations.putAll("userInfo", map);
// 获取一条数据
String name = hashOperations.get("userInfo", "name");
System.out.println(name);
// 获取多条数据
List<String> keys = new ArrayList<>();
keys.add("age");
keys.add("sex");
List<String> resultlist =hashOperations.multiGet("userInfo", keys);
for (String str : resultlist) {
System.out.println(str);
}
// 获取Hash类型所有的数据
Map<String, String> userMap = hashOperations.entries("userInfo");
for (Entry<String, String> userInfo : userMap.entrySet()) {
System.out.println(userInfo.getKey() + "--" + userInfo.getValue());
}
// 删除 用于删除hash类型数据
hashOperations.delete("userInfo", "name");
}
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");
}
6. 获取所有key+设置key失效时间
获取所有key&删除
// 获取所有key
@Test
public void testAllKeys() {
// 当前库key的名称
Set<String> keys = redisTemplate.keys("*");
for (String key: keys) {
System.out.println(key);
}
}
// 删除
@Test
public void testDelete() {
// 删除 通用 适用于所有数据类型
redisTemplate.delete("score");
}
设置key的失效时间
@Test
public void testEx() {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
// 方法一:插入一条数据并设置失效时间
valueOperations.set("code", "abcd", 180, TimeUnit.SECONDS);
// 方法二:给已存在的key设置失效时间
boolean flag = redisTemplate.expire("code", 180, TimeUnit.SECONDS);
// 获取指定key的失效时间
Long l = redisTemplate.getExpire("code");
}
7. 通用操作
/**
* 通用操作,针对不同的数据类型都可以操作
*/
@Test
public void testCommon(){
//获取Redis中所有的key
Set<String> keys = redisTemplate.keys("*");
for (String key : keys) {
System.out.println(key);
}
//判断某个key是否存在
Boolean project = redisTemplate.hasKey("itcast");
System.out.println(project);
//删除指定key
redisTemplate.delete("myZset");
//获取指定key对应的value的数据类型
DataType dataType = redisTemplate.type("myset");
System.out.println(dataType.name());
}
九、SpringDataRedis整合哨兵
application.yml
spring:
redis:
# Redis服务器地址
host: 192.168.10.100
# Redis服务器端口
port: 6379
# 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
#哨兵模式
sentinel:
#主节点名称
master: mymaster
#节点
nodes: 192.168.10.100:26379,192.168.10.100:26380,192.168.10.100:26381
Bean注解配置
@Bean
public RedisSentinelConfiguration redisSentinelConfiguration(){
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
// 主节点名称
.master("mymaster")
// 主从服务器地址
.sentinel("192.168.10.100", 26379)
.sentinel("192.168.10.100", 26380)
.sentinel("192.168.10.100", 26381);
// 设置密码
sentinelConfig.setPassword("root");
return sentinelConfig;
}
十、知识小结
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做
SpringDataRedis,官网地址:Spring Data Redis
- 提供了对不同Redis客户端的整合(Lettuce和Jedis)
- 提供了RedisTemplate统一API来操作Redis
- 支持Redis的发布订阅模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
- 支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。
并且将不同数据类型的操作API封装到了不同的类型中: