Spring Boot Redis
开发环境
开发工具: Intellij IDEA 2018.2.6
springboot: 2.0.7.RELEASE
jdk: 1.8.0_192
maven: 3.6.0
redis: 4.0.12
redis 简介
什么是 redis ?
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
搭建项目
- pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<groupId>com.andy</groupId>
<artifactId>spring-boot-redis</artifactId>
<version>1.0.7.RELEASE</version>
<modelVersion>4.0.0</modelVersion>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Cairo-SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.6.RELEASE</version>
<configuration>
<!--<mainClass>${start-class}</mainClass>-->
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
- application.yml
server:
port: 8081
servlet:
context-path: /
spring:
application:
name: spring-redis
redis:
# 数据库索引
database: 3
# 连接超时时间
timeout: 10000ms
# ip地址
host: 127.0.0.1
# 端口
port: 6379
# 密码
# password:
jedis:
pool:
# 最大连接数
max-active: 8
# 最大阻塞等待时间(负数表示没限制)
max-wait: -1ms
# 最大空闲
max-idle: 8
# 最小空闲
min-idle: 0
- 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
/**
* @author Leone
* @since 2018-05-11
**/
@EnableCaching
@SpringBootApplication
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}
- RedisConfig.java
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* <p> redis配置
*
* @author Leone
* @since 2018-07-19
**/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
// 生成一个默认配置,通过config对象即可对缓存进行自定义配置
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// 设置缓存的默认过期时间,也是使用Duration设置
config = config.entryTtl(Duration.ofMinutes(1))
// 不缓存空值
.disableCachingNullValues();
// 设置一个初始化的缓存空间set集合
Set<String> cacheNames = new HashSet<>();
cacheNames.add("my-redis-cache1");
cacheNames.add("my-redis-cache2");
// 对每个缓存空间应用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("my-redis-cache1", config);
configMap.put("my-redis-cache2", config.entryTtl(Duration.ofSeconds(120)));
// 使用自定义的缓存配置初始化一个cacheManager
return RedisCacheManager.builder(factory)
// 注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
.initialCacheNames(cacheNames)
.withInitialCacheConfigurations(configMap)
.build();
}
/**
* 设置 redis 入库 各种类型 k v 序列化
*
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// RedisSerializer<String> stringSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
- User.java
import java.io.Serializable;
import java.util.Date;
/**
* <p>
*
* @author Leone
* @since 2018-03-02
**/
public class User implements Serializable {
private Long userId;
private String account;
private String password;
private String description;
private Integer age;
private Date createTime;
private boolean deleted;
public User() {
}
public User(Long userId, String account, String password, String description, Integer age, Date createTime, Boolean deleted) {
this.userId = userId;
this.account = account;
this.password = password;
this.description = description;
this.age = age;
this.createTime = createTime;
this.deleted = deleted;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
}
- RedisPrefix.java
/**
* redis 前缀生成器
*
* @author Leone
* @since 2018-07-08
**/
public class RedisPrefix {
public static String userCatch(String uuid) {
return "app.user:" + uuid;
}
}
- RedisController.java
import com.andy.redis.service.RedisCacheService;
import com.andy.redis.service.RedisService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author Leone
* @since 2018-07-08
**/
@RestController
@RequestMapping("/api/redis")
public class RedisController {
@Resource
private RedisService redisService;
@Resource
private RedisCacheService redisCacheService;
@GetMapping("/list")
public String list() {
return "list: " + redisService.list() + " !";
}
@GetMapping("/value")
public String value() {
return "value: " + redisService.value() + " !";
}
@GetMapping("/set")
public String set() {
return "set " + redisService.set() + " !";
}
@GetMapping("/zSet")
public String zSet() {
return "zSet " + redisService.zSet() + " !";
}
@GetMapping("/hash")
public String hash() {
return "hash " + redisService.hash() + " !";
}
@GetMapping("/catch")
public String userCatch() {
return redisCacheService.userCatch();
}
}
- RedisService.java
import com.andy.redis.config.RedisPrefix;
import com.andy.redis.util.EntityFactory;
import com.andy.redis.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* <p>
*
* @author Leone
* @since 2018-08-11
**/
@Slf4j
@Service
public class RedisService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 相当于队列操作
*
* @return
*/
public long list() {
log.info("list:{}", 1);
for (int i = 0; i < 10; i++) {
String key = RedisPrefix.userCatch("list"), value = RandomUtil.getName();
Long push = redisTemplate.opsForList().leftPush(key, value);
log.info("leftPush key:[{}] -- value:[{}]", key, value);
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 9; i++) {
Object result = redisTemplate.opsForList().rightPop(RedisPrefix.userCatch("list"));
log.info("leftPop key:[{}] -- value:[{}]", i, result);
}
return 1;
}
/**
* set 普通 字符串或对象 类型数据
*
* @return
*/
public long value() {
log.info("value:{}", 1);
redisTemplate.opsForValue().set(RedisPrefix.userCatch(RandomUtil.getNum(6)), EntityFactory.getUser(), 120, TimeUnit.SECONDS);
return 1;
}
/**
* set 操作
*
* @return
*/
public long set() {
log.info("set:{}", 1);
// set值
Long add = redisTemplate.opsForSet().add("key1", "dd", "bb", "ee", "aa");
// 获取值
Set<Object> resultSet = redisTemplate.opsForSet().members("key1");
// 获取变量中值的长度
Long size = redisTemplate.opsForSet().size("key1");
// 随机获取变量中的元素
Object randomVal = redisTemplate.opsForSet().randomMember("key1");
// 随机获取变量中指定个数的元素
List<Object> randomValues = redisTemplate.opsForSet().randomMembers("key1", 3);
// 检查给定的元素是否在变量中
Boolean isMember = redisTemplate.opsForSet().isMember("key1", "ff");
// 转移变量的元素值到目的变量
//Boolean move = redisTemplate.opsForSet().move("key1", "aa", "ee");
// 弹出变量中的元素
//List<Object> key1 = redisTemplate.opsForSet().pop("key1", 1);
// 批量移除变量中的元素。
//Long remove = redisTemplate.opsForSet().remove("key1", "aa", "bb");
// 匹配获取键值对,ScanOptions.NONE为获取全部键值对;ScanOptions.scanOptions().match("C").build()匹配获取键位map1的键值对,不能模糊匹配。
/*Cursor<Object> cursor = redisTemplate.opsForSet().scan("setValue", ScanOptions.scanOptions().match("c").build());
while (cursor.hasNext()){
Object object = cursor.next();
System.out.println("通过scan(K key, ScanOptions options)方法获取匹配的值:" + object);
}*/
log.info("size: {} randomVal: {} randomValues: {} resultSet: {} isMember: {}", size, randomVal, randomValues, resultSet, isMember);
return 1;
}
public long zSet() {
log.info("zSet:{}", 1);
redisTemplate.opsForZSet().add(RedisPrefix.userCatch(RandomUtil.getNum(6)), EntityFactory.getUser(), 3);
redisTemplate.opsForZSet().add("zSetValue", "A", 1);
redisTemplate.opsForZSet().add("zSetValue", "B", 3);
redisTemplate.opsForZSet().add("zSetValue", "C", 2);
redisTemplate.opsForZSet().add("zSetValue", "D", 5);
// 获取指定区间的元素
Set zSetValue = redisTemplate.opsForZSet().range("zSetValue", 0, -1);
log.info("range: {}", zSetValue);
// 用于获取满足非score的排序取值。这个排序只有在有相同分数的情况下才能使用,如果有不同的分数则返回值不确定。
RedisZSetCommands.Range range = new RedisZSetCommands.Range();
// range.gt("A");
range.lt("D");
zSetValue = redisTemplate.opsForZSet().rangeByLex("zSetValue", range);
log.info("rangeByLex: {}", zSetValue);
// 通过TypedTuple方式新增数据
ZSetOperations.TypedTuple<Object> typedTuple1 = new DefaultTypedTuple<>("E", 6.0);
ZSetOperations.TypedTuple<Object> typedTuple2 = new DefaultTypedTuple<>("F", 7.0);
ZSetOperations.TypedTuple<Object> typedTuple3 = new DefaultTypedTuple<>("G", 5.0);
Set<ZSetOperations.TypedTuple<Object>> typedTupleSet = new HashSet<>();
typedTupleSet.add(typedTuple1);
typedTupleSet.add(typedTuple2);
typedTupleSet.add(typedTuple3);
redisTemplate.opsForZSet().add("typedTupleSet", typedTupleSet);
zSetValue = redisTemplate.opsForZSet().range("typedTupleSet", 0, -1);
log.info("添加元素:{}", zSetValue);
long count = redisTemplate.opsForZSet().count("zSetValue", 1, 5);
log.info("获取区间值的个数:{}", count);
return 1;
}
/**
* @return
*/
public long hash() {
log.info("hash:{}", 1);
// put() 添加
redisTemplate.opsForHash().put("he1", "key1", EntityFactory.getUser());
redisTemplate.opsForHash().put("he1", "key2", EntityFactory.getUser());
redisTemplate.opsForHash().put("he1", "key3", EntityFactory.getUser());
Map<Object, Object> entries = redisTemplate.opsForHash().entries("he1");
log.info("put:{}", entries);
// putAll() 批量添加
Map<String, Object> param = new HashMap<>();
param.put("key1", EntityFactory.getUser());
param.put("key2", EntityFactory.getUser());
param.put("key3", EntityFactory.getUser());
redisTemplate.opsForHash().putAll("he2", param);
log.info("putAll:{}", redisTemplate.opsForHash().entries("he2"));
// delete() 删除指定key
redisTemplate.opsForHash().delete("he3", "key1");
log.info("delete:{}", redisTemplate.opsForHash().entries("he3"));
// hasKey() 判断某个key是否存在
log.info("hasKey:{}", redisTemplate.opsForHash().hasKey("he2", "key2"));
// get() 获取值
log.info("get:{}", redisTemplate.opsForHash().get("he2", "key1"));
// multiGet() 批量获取
log.info("multiGet:{}", redisTemplate.opsForHash().multiGet("he2", Arrays.asList("key1", "key2")));
// 获取所有key
log.info("keys:{}", redisTemplate.opsForHash().keys("he2"));
// 获取所有key size
log.info("size:{}", redisTemplate.opsForHash().size("he2"));
// 获取所有key values
log.info("values:{}", redisTemplate.opsForHash().values("he2"));
Cursor<Map.Entry<Object, Object>> scan = redisTemplate.opsForHash().scan("he2", ScanOptions.NONE);
while (scan.hasNext()) {
Map.Entry<Object, Object> entry = scan.next();
log.info("key:{} -- value:{}", entry.getKey(), entry.getValue());
}
return 1;
}
}