SpringBoot坚持学习第六天:集成Redis
一、Redis基本操作
先导入我的Redis储备知识:从头开始学Redis
Redis 支持多种数据类型,字符串string、哈希hash、列表list、集合set、有序集合zset。
二、在SpringBoot中集成Redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
在配置文件中需要配置我们的Redis的服务器地址
# Redis 数据库索引(默认为 0)
spring.redis.database=0
# Redis 服务器地址
spring.redis.host=localhost
# Redis 服务器连接端口
spring.redis.port=6379
# Redis 服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
三、具体使用
首先编写一个实体,需要实现序列化接口,否则不能够加入到缓存。
@Data //get set hashcode equals toString
@Builder //build
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Long id;
private String username;
private String password;
}
@Test
public void testBuilder() {
User user = User.builder().id(1L).username("jay").password("3333").build();
System.out.println(user);
/**
* User(id=1, username=jay, password=3333)
*/
}
原来使用Redis就是这么简单,直接注入就行了。注入后,就能使用Redis客户端提供的相关API方法。
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestRedisTemplate {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testString() {
ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set("username", "jay");
Assert.assertEquals("jay", operations.get("username"));
}
@Test
public void testSaveUser() {
ValueOperations<String, User> operations = redisTemplate.opsForValue();
User user = new User(1L,"jay","3333");
operations.set("mykey",user);
User u = operations.get("mykey");
System.out.println(u);
}
}
有点封装意识的开发人员就会意识到,我们得创建一个类似RedisService这个类,用于封装RedisTemplate这个类。最后提供给客户端使用的都是最简单的接口。
(1)字符串string
某个字符串 映射 某个值 。 可以理解为Java中的String类型,但是这个字符串对象的值是"abc"。
@Service
public class RedisService {
private Logger LOGGER = LoggerFactory.getLogger(RedisService.class);
/**
* 注入redis的客户端
*/
@Autowired
private RedisTemplate redisTemplate;
public boolean set(final String key, Object value) {
boolean result = false;
try {
//获取redis的操作普通键值对的操作对象
ValueOperations<String, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
LOGGER.error("set error: key {},value {}", key, value, e);
}
return result;
}
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
//获取redis的操作普通键值对的操作对象
ValueOperations<String, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
//设置过期时间,单位毫秒
redisTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
result = true;
} catch (Exception e) {
LOGGER.error("set error: key {},value {}", key, value, e);
}
return result;
}
public Object get(final String key) {
ValueOperations<String, Object> operations = redisTemplate.opsForValue();
return operations.get(key);
}
}
@Test
public void set(){
redisService.set("mykey","myValue");
Assert.assertEquals("myValue",redisService.get("mykey"));
}
@Test
public void testExpire() throws InterruptedException {
User user = new User(1L, "jay", "3333");
redisService.set("mykey", user, 100L);
Thread.sleep(1000);
Assert.assertNotEquals(user, redisService.get("mykey"));
}
删除某个字符串 ,先判断这个字符串是否存在,如果存在在删除
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
(2)哈希hash
keyMap --- fieldKey --- value
public void hashSet(String key, Object fieldKey, Object value) {
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key, fieldKey, value);
}
public Object hashGet(final String key, final Object fieldKey) {
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key, fieldKey);
}
@Test
public void hashSet(){
redisService.hashSet("jay","age",22);
Assert.assertEquals(22,redisService.hashGet("jay","age"));
}
(3)列表List
有序的队列,支持从左边添加,也支持从队列右侧添加。
使用 stringRedisTemplate.opsForList() 可以获取 ListOperations<String, String> listOperations Redis 列表对象,该列表是个简单的字符串列表,可以支持从左侧添加,也可以支持从右侧添加
public void push(final String key, Object value) {
//String泛型视为list的name,Object泛型视为即将要存储到这个list中的值
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(key, value);
}
public List<Object> range(final String key, int start, int end) {
ListOperations<String, Object> list = redisTemplate.opsForList();
//获取某个list集合的指定范围索引
return list.range(key, start, end);
}
@Test
public void testList() {
redisService.push("myList", "a");
redisService.push("myList", "b");
redisService.push("myList", "c");
List<Object> objectList = redisService.range("myList", 0, -1);
Assert.assertEquals(3, objectList.size());
}
(4)集合set
Redis Set 对外提供的功能与 List 类似是一个列表的功能,特殊之处在于 Set 是可以自动去重的,当你需要存储一个列表数据,又不希望出现重复数据时,Set 是一个很好的选择,并且 Set 提供了判断某个成员是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的。
public void setAdd(final String key, Object value) {
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key, value);
}
public Set<Object> setMembers(final String key) {
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
public boolean setIsMember(final String key, final Object value) {
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.isMember(key, value);
}
@Test
public void testSet() {
redisService.setAdd("mySet", "a");
redisService.setAdd("mySet", "b");
redisService.setAdd("mySet", "b");
redisService.setAdd("mySet", "c");
Assert.assertEquals(3, redisService.setMembers("mySet").size());
Assert.assertTrue(redisService.setIsMember("mySet","c"));
}
(5)有序集合zset
使用 Zset 的时候需要额外的输入一个参数 Score,Zset 会自动根据 Score 的值对集合进行排序。也能够取出指定权重范围内的数据。
public void zsetAdd(final String key, Object value, double score) {
ZSetOperations zset = redisTemplate.opsForZSet();
zset.add(key, value, score);
}
public Set<Object> zsetRange(final String key, int start, int end) {
ZSetOperations zset = redisTemplate.opsForZSet();
return zset.range(key, start, end);
}
public Set<Object> zsetRangeByScore(final String key, double score, double score1) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, score, score1);
}
@Test
public void testAddZset(){
redisService.zsetAdd("myZset","a",1);
redisService.zsetAdd("myZset","c",3);
redisService.zsetAdd("myZset","b",2);
//获取所有,顺序是 a b c
redisService.zsetRange("myZset",0,-1);
//获取了权重2到3之间的,顺序是 b c
redisService.zsetRangeByScore("myZset",2,3);
}
--------------------------------------------------------------------------------------------------------------------------
再把本次编写的RedisService整个贴上。诶,出租房里真冷,手都快僵了。虽然在重复造轮子,各个公司肯定有这类似的Redis工具类,但是这个过程还是要自己手写一遍,下次见到大牛的Redis工具类才能见贤思齐。
package com.safesoft.redisdemo.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author jay.zhou
* @date 2019/1/6
* @time 13:39
*/
@Service
public class RedisService {
private Logger LOGGER = LoggerFactory.getLogger(RedisService.class);
/**
* 注入redis的客户端
*/
@Autowired
private RedisTemplate redisTemplate;
public boolean set(final String key, Object value) {
boolean result = false;
try {
//获取redis的操作普通键值对的操作对象
ValueOperations<String, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
LOGGER.error("set error: key {},value {}", key, value, e);
}
return result;
}
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
//获取redis的操作普通键值对的操作对象
ValueOperations<String, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
//设置过期时间
redisTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
result = true;
} catch (Exception e) {
LOGGER.error("set error: key {},value {}", key, value, e);
}
return result;
}
public Object get(final String key) {
ValueOperations<String, Object> operations = redisTemplate.opsForValue();
return operations.get(key);
}
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
public void hashSet(String key, Object fieldKey, Object value) {
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key, fieldKey, value);
}
public Object hashGet(final String key, final Object fieldKey) {
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key, fieldKey);
}
public void push(final String key, Object value) {
//String泛型视为list的name,Object泛型视为即将要存储到这个list中的值
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(key, value);
}
public List<Object> range(final String key, int start, int end) {
ListOperations<String, Object> list = redisTemplate.opsForList();
//获取某个list集合的指定范围索引
return list.range(key, start, end);
}
public void setAdd(final String key, Object value) {
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key, value);
}
public Set<Object> setMembers(final String key) {
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
public boolean setIsMember(final String key, final Object value) {
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.isMember(key, value);
}
public void zsetAdd(final String key, Object value, double score) {
ZSetOperations zset = redisTemplate.opsForZSet();
zset.add(key, value, score);
}
public Set<Object> zsetRange(final String key, int start, int end) {
ZSetOperations zset = redisTemplate.opsForZSet();
return zset.range(key, start, end);
}
public Set<Object> zsetRangeByScore(final String key, double score, double score1) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, score, score1);
}
}