Redis安装参考:【Redis】安装及简单使用
一、Redis整合
1、创建SpringBoot项目
引入SpringBoot的redis启动器:
1 <!-- SpringBoot整合redis --> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-data-redis</artifactId> 5 </dependency>
查看依赖,SpringBoot默认使用的是Lettuce作为Redis客户端(可以自己修改引入Jedis作为Redis客户端)
完整pom文件如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>com.test.redis</groupId> 8 <artifactId>test-springboot-redis</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 11 <parent> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starter-parent</artifactId> 14 <version>2.2.5.RELEASE</version> 15 </parent> 16 17 <properties> 18 <maven.compiler.source>8</maven.compiler.source> 19 <maven.compiler.target>8</maven.compiler.target> 20 </properties> 21 22 23 <dependencies> 24 <dependency> 25 <groupId>org.springframework.boot</groupId> 26 <artifactId>spring-boot-starter</artifactId> 27 </dependency> 28 29 <!-- SpringBoot整合redis --> 30 <dependency> 31 <groupId>org.springframework.boot</groupId> 32 <artifactId>spring-boot-starter-data-redis</artifactId> 33 </dependency> 34 35 <!-- Redis客户端lettuce 连接池依赖项 --> 36 <dependency> 37 <groupId>org.apache.commons</groupId> 38 <artifactId>commons-pool2</artifactId> 39 </dependency> 40 41 <!-- Json Jar包 --> 42 <dependency> 43 <groupId>com.fasterxml.jackson.core</groupId> 44 <artifactId>jackson-databind</artifactId> 45 <version>2.10.2</version> 46 </dependency> 47 48 <dependency> 49 <groupId>org.springframework.boot</groupId> 50 <artifactId>spring-boot-starter-test</artifactId> 51 <scope>test</scope> 52 </dependency> 53 54 </dependencies> 55 56 </project>
2、application.yml配置redis连接地址
redis单机配置
1 spring: 2 redis: 3 # 主机地址 4 host: 127.0.0.1 5 # 默认端口 6 port: 6379 7 # 密码 8 password:123456
redis哨兵模式配置
1 spring: 2 redis: 3 database: 0 # Redis数据库索引(默认为0) 4 #host: 192.168.1.8 5 #port: 6379 6 password: 123456 7 sentinel: 8 master: mymaster # Redis配置的 master名称 9 nodes: 10 - 192.168.1.8:9001 11 - 192.168.1.8:9002 12 - 192.168.1.8:9003 13 # 或者 14 # 192.168.1.8:9001,192.168.1.8:9002,192.168.1.8:9003
redis集群模式配置
1 spring: 2 redis: 3 database: 0 # Redis数据库索引(默认为0) 4 #host: 192.168.1.8 5 #port: 6379 6 password: 123456 7 cluster: 8 nodes: 9 - 192.168.1.8:9001 10 - 192.168.1.8:9002 11 - 192.168.1.8:9003 12 # 或者 13 # 192.168.1.8:9001,192.168.1.8:9002,192.168.1.8:9003
redis连接池配置
1 spring: 2 redis: 3 database: 0 4 timeout: 3000 5 password: 123456 6 # 单节点模式 7 host: 127.0.0.1 8 port: 6379 9 10 # 连接池,默认使用lettuce客户端redis连接池 11 lettuce: 12 pool: 13 max-idle: 8 # 连接池中的最大空闲连接数 14 min-idle: 0 # 连接池中的最小空闲连接数 15 max-active: 8 # 连接池最大连接数(使用负值表示没有限制) 16 max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制) 17 18 # jedis: 19 # pool: 20 # max-idle: 8 # 连接池中的最大空闲连接数 21 # min-idle: 0 # 连接池中的最小空闲连接数 22 # max-active: 8 # 连接池最大连接数(使用负值表示没有限制) 23 # max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
3、Redis自动配置原理
由于SpringBoot引入了 RedisAutoConfiguration 类,此类事redis的自动配置来,可以看到它自动注册了 RedisTemplate 和 StringRedisTemplate,2个类
所以在SpringBoot项目中就可以使用 redisTemplate和stringRedisTemplate 2个对象来操作Redis
1 @Configuration(proxyBeanMethods = false) 2 @ConditionalOnClass(RedisOperations.class) 3 @EnableConfigurationProperties(RedisProperties.class) 4 @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) 5 public class RedisAutoConfiguration { 6 7 @Bean 8 @ConditionalOnMissingBean(name = "redisTemplate") 9 public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) 10 throws UnknownHostException { 11 RedisTemplate<Object, Object> template = new RedisTemplate<>(); 12 template.setConnectionFactory(redisConnectionFactory); 13 return template; 14 } 15 16 @Bean 17 @ConditionalOnMissingBean 18 public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) 19 throws UnknownHostException { 20 StringRedisTemplate template = new StringRedisTemplate(); 21 template.setConnectionFactory(redisConnectionFactory); 22 return template; 23 } 24 25 }
创建2个模版对象, 需要 RedisConnectionFactory 连接工厂对象, 这个对象是在 RedisAutoConfiguration 上 @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) 的 LettuceConnectionConfiguration 配置类中导入的, 查看连接配置类
1 @Configuration(proxyBeanMethods = false) 2 @ConditionalOnClass(RedisClient.class) 3 class LettuceConnectionConfiguration extends RedisConnectionConfiguration { 4 5 @Bean 6 @ConditionalOnMissingBean(RedisConnectionFactory.class) 7 LettuceConnectionFactory redisConnectionFactory( 8 ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers, 9 ClientResources clientResources) throws UnknownHostException { 10 LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(builderCustomizers, clientResources, 11 getProperties().getLettuce().getPool()); 12 return createLettuceConnectionFactory(clientConfig); 13 } 14 15 private LettuceConnectionFactory createLettuceConnectionFactory(LettuceClientConfiguration clientConfiguration) { 16 if (getSentinelConfig() != null) { 17 return new LettuceConnectionFactory(getSentinelConfig(), clientConfiguration); 18 } 19 if (getClusterConfiguration() != null) { 20 return new LettuceConnectionFactory(getClusterConfiguration(), clientConfiguration); 21 } 22 return new LettuceConnectionFactory(getStandaloneConfig(), clientConfiguration); 23 } 24 ...... 25 }
4、使用redisTemplate和stringRedisTemplate操作Redis
编写测试类
1 package com.test.redis; 2 3 import com.test.redis.entity.Employee; 4 import org.junit.Test; 5 import org.junit.runner.RunWith; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.boot.test.context.SpringBootTest; 8 import org.springframework.context.ApplicationContext; 9 import org.springframework.data.redis.core.RedisTemplate; 10 import org.springframework.data.redis.core.StringRedisTemplate; 11 import org.springframework.test.context.junit4.SpringRunner; 12 13 import java.util.HashMap; 14 import java.util.Map; 15 16 @RunWith(SpringRunner.class) 17 @SpringBootTest 18 public class TestApplication { 19 20 @Autowired 21 ApplicationContext context; 22 23 // 处理Object类型的key和value数据 24 @Autowired 25 RedisTemplate redisTemplate; 26 27 // 处理String类型的key和value数据 28 @Autowired 29 StringRedisTemplate stringRedisTemplate; 30 31 // 使用 redisTemplate 处理对象 32 @Test 33 public void terst1(){ 34 Employee emp = new Employee(1, "小明"); 35 redisTemplate.opsForValue().set("emp", emp); 36 Employee emp2 = (Employee) redisTemplate.opsForValue().get("emp"); 37 System.out.println(emp2); 38 } 39 40 // 使用 stringRedisTemplate 处理字符串 41 @Test 42 public void test2(){ 43 stringRedisTemplate.opsForValue().set("msg", "hello world"); 44 String msg = stringRedisTemplate.opsForValue().get("msg"); 45 System.out.println(msg); 46 } 47 }
在redis服务器上查看
测试方法test01中,
保存对象时,会对key进行序列化, "emp" ==> "\xac\xed\x00\x05t\x00\x03emp"
而且也会对value(Employee对象)序列化,所以Employee类必须实现Serializable接口,否则会报错,下图为emp对象保存在redis中的数据。
5、将数据以json的方式保存
a、自己将对象转为json(此种就时将对象转成json字符串)
b、redisTmplate默认规则
分析redisTmplate默认规则:在RedisAutoConfiguration类中,RedisTemplate是通过简单的new出来的,其中defaultSerializer默认序列化器是使用JDK自带的,查看RedisTemplate类
1 public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware { 2 ... 3 4 public RedisTemplate() {} 5 6 @Override 7 public void afterPropertiesSet() { 8 9 super.afterPropertiesSet(); 10 boolean defaultUsed = false; 11 12 if (defaultSerializer == null) { 13 // 使用jdk自带的解析器 14 defaultSerializer = new JdkSerializationRedisSerializer( 15 classLoader != null ? classLoader : this.getClass().getClassLoader()); 16 } 17 18 if (enableDefaultSerializer) { 19 20 if (keySerializer == null) { 21 // key序列化器 22 keySerializer = defaultSerializer; 23 defaultUsed = true; 24 } 25 if (valueSerializer == null) { 26 // value序列化器 27 valueSerializer = defaultSerializer; 28 defaultUsed = true; 29 } 30 if (hashKeySerializer == null) { 31 hashKeySerializer = defaultSerializer; 32 defaultUsed = true; 33 } 34 if (hashValueSerializer == null) { 35 hashValueSerializer = defaultSerializer; 36 defaultUsed = true; 37 } 38 } 39 40 ... 41 } 42 ... 43 }
查看RedisTemplate类,使用的序列化器是从RedisSerializer这个类中得到的
1 public class StringRedisTemplate extends RedisTemplate<String, String> { 2 3 4 public StringRedisTemplate() { 5 // 设置序列化器 6 setKeySerializer(RedisSerializer.string()); 7 setValueSerializer(RedisSerializer.string()); 8 setHashKeySerializer(RedisSerializer.string()); 9 setHashValueSerializer(RedisSerializer.string()); 10 } 11 ...... 12 }
查看RedisSerializer类-Redis序列化类,这个使用引入spring-boot-starter-data-redis的jar包提供的
1 // Redis序列化器 2 public interface RedisSerializer<T> { 3 4 static RedisSerializer<Object> java() { 5 return java(null); 6 } 7 8 static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) { 9 return new JdkSerializationRedisSerializer(classLoader); 10 } 11 // json序列化器,使用ObjectMapper对象处理json,需要引入依赖 12 static RedisSerializer<Object> json() { 13 return new GenericJackson2JsonRedisSerializer(); 14 } 15 // string序列化器 16 static RedisSerializer<String> string() { 17 return StringRedisSerializer.UTF_8; 18 } 19 20 static RedisSerializer<byte[]> byteArray() { 21 return ByteArrayRedisSerializer.INSTANCE; 22 } 23 }
自己注入一个redisTemplate
如果想将数据以json的方式保存在redis中,需要自己注入一个redisTemplate,且此redisTemplate使用json的序列化器。
1、修改默认序列化器
1 @Bean 2 public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) 3 throws UnknownHostException { 4 RedisTemplate<Object, Object> template = new RedisTemplate<>(); 5 template.setConnectionFactory(redisConnectionFactory); 6 7 // 设置默认的序列化器,修改默认的序列化器,会对所有的key和value有效 8 template.setDefaultSerializer(RedisSerializer.json()); 9 // // 设置key的序列化器 10 // template.setKeySerializer(RedisSerializer.string()); 11 // // 设置value的序列化器 12 // template.setValueSerializer(RedisSerializer.json()); 13 14 return template; 15 }
结果: 值转化成json了,当是key包含了冒号,而普通的key没有包含
2、key使用字符串序列化器,值使用json序列化器
1 @Bean 2 public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) 3 throws UnknownHostException { 4 RedisTemplate<Object, Object> template = new RedisTemplate<>(); 5 template.setConnectionFactory(redisConnectionFactory); 6 7 // 设置默认的序列化器,修改默认的序列化器,会对所有的key和value有效 8 // template.setDefaultSerializer(RedisSerializer.json()); 9 // 设置key的序列化器为字符串序列化器 10 template.setKeySerializer(RedisSerializer.string()); 11 template.setHashKeySerializer(RedisSerializer.string()); 12 13 // 设置value的序列化器为json序列化器 14 template.setValueSerializer(RedisSerializer.json()); 15 template.setHashValueSerializer(RedisSerializer.json()); 16 17 return template; 18 }
结果: key与普通的key相同,值也为json格式
二、StringRedisTemplate与RedisTemplate操作
1 private ValueOperations<K, V> valueOps;
2 private HashOperations<K, V> hashOps;
3 private ListOperations<K, V> listOps;
4 private SetOperations<K, V> setOps;
5 private ZSetOperations<K, V> zSetOps;
RedisTemplate中定义了对5种数据结构操作
1 redisTemplate.opsForValue(); // 操作字符串 2 redisTemplate.opsForHash(); // 操作hash 3 redisTemplate.opsForList(); // 操作list 4 redisTemplate.opsForSet(); // 操作set 5 redisTemplate.opsForZSet(); // 操作有序set
StringRedisTemplate继承自RedisTemplate,也一样拥有上面这些操作。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
Redis客户端命令对应的RedisTemplate中的方法列表:
String类型结构
|
|
Redis
|
RedisTemplate rt
|
set key value
|
rt.opsForValue().set("key","value")
|
get key
|
rt.opsForValue().get("key")
|
del key
|
rt.delete("key")
|
strlen key
|
rt.opsForValue().size("key")
|
getset key value
|
rt.opsForValue().getAndSet("key","value")
|
getrange key start end
|
rt.opsForValue().get("key",start,end)
|
append key value
|
rt.opsForValue().append("key","value")
|
Hash结构
|
|
hmset key field1 value1 field2 value2...
|
rt.opsForHash().putAll("key",map) //map是一个集合对象
|
hset key field value
|
rt.opsForHash().put("key","field","value")
|
hexists key field
|
rt.opsForHash().hasKey("key","field")
|
hgetall key
|
rt.opsForHash().entries("key") //返回Map对象
|
hvals key
|
rt.opsForHash().values("key") //返回List对象
|
hkeys key
|
rt.opsForHash().keys("key") //返回List对象
|
hmget key field1 field2...
|
rt.opsForHash().multiGet("key",keyList)
|
hsetnx key field value
|
rt.opsForHash().putIfAbsent("key","field","value"
|
hdel key field1 field2
|
rt.opsForHash().delete("key","field1","field2")
|
hget key field
|
rt.opsForHash().get("key","field")
|
|
|
List结构
|
|
lpush list node1 node2 node3...
|
rt.opsForList().leftPush("list","node")
|
rt.opsForList().leftPushAll("list",list) //list是集合对象
|
|
rpush list node1 node2 node3...
|
rt.opsForList().rightPush("list","node")
|
rt.opsForList().rightPushAll("list",list) //list是集合对象
|
|
lindex key index
|
rt.opsForList().index("list", index)
|
llen key
|
rt.opsForList().size("key")
|
lpop key
|
rt.opsForList().leftPop("key")
|
rpop key
|
rt.opsForList().rightPop("key")
|
lpushx list node
|
rt.opsForList().leftPushIfPresent("list","node")
|
rpushx list node
|
rt.opsForList().rightPushIfPresent("list","node")
|
lrange list start end
|
rt.opsForList().range("list",start,end)
|
lrem list count value
|
rt.opsForList().remove("list",count,"value")
|
lset key index value
|
rt.opsForList().set("list",index,"value")
|
Set结构
|
|
sadd key member1 member2...
|
rt.boundSetOps("key").add("member1","member2",...)
|
rt.opsForSet().add("key", set) //set是一个集合对象
|
|
scard key
|
rt.opsForSet().size("key")
|
sidff key1 key2
|
rt.opsForSet().difference("key1","key2") //返回一个集合对象
|
sinter key1 key2
|
rt.opsForSet().intersect("key1","key2")//同上
|
sunion key1 key2
|
rt.opsForSet().union("key1","key2")//同上
|
sdiffstore des key1 key2
|
rt.opsForSet().differenceAndStore("key1","key2","des")
|
sinter des key1 key2
|
rt.opsForSet().intersectAndStore("key1","key2","des")
|
sunionstore des key1 key2
|
rt.opsForSet().unionAndStore("key1","key2","des")
|
sismember key member
|
rt.opsForSet().isMember("key","member")
|
smembers key
|
rt.opsForSet().members("key")
|
spop key
|
rt.opsForSet().pop("key")
|
srandmember key count
|
rt.opsForSet().randomMember("key",count)
|
srem key member1 member2...
|
rt.opsForSet().remove("key","member1","member2",...)
|