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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>redis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<lombok.version>1.18.22</lombok.version>
<jackson-annotations-version>2.10.1</jackson-annotations-version>
<jackson.core.version>2.10.1</jackson.core.version>
<jackson.databind.version>2.10.1</jackson.databind.version>
<fastjson.version>1.2.66</fastjson.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson-annotations-version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.databind.version}</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.core.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.10.6</version>
</dependency>
<!-- redis依赖commons-pool 这个依赖一定要添加 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.72.Final</version>
</dependency>
</dependencies>
</project>
application.yml
spring:
redis:
port: 6379
host: 127.0.0.1
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 8
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 0
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: 1000
# 关闭超时时间
shutdown-timeout: 100
application.properties
redisson.host.config=redis://127.0.0.1:6379
redis的配置
package com.example.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.cache.RedisCacheWriter;
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.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import javax.annotation.PostConstruct;
@Configuration
@Slf4j
//使用 @Cacheable, @CachePut, @CacheEvit
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
RedisTemplate redisTemplate;
//任务池
private ThreadPoolTaskScheduler taskScheduler;
/**
* redis连接工厂
*/
@Autowired
RedisConnectionFactory redisConnectionFactory;
@PostConstruct
public void init() {
initRedisTemplate();
}
public void initRedisTemplate() {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
/**
* 创建线程池,等待线程处理redis的消息
* @return
*/
@Bean
public ThreadPoolTaskScheduler initTaskScheduler() {
if(taskScheduler!=null) {
return taskScheduler;
}
taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(20);
return taskScheduler;
}
}
redisson的配置
package com.example.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.TransportMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* @description:
* @author: chengjiapeng
* @date 2023/7/6 10:46
*/
@Configuration
public class RedissonConfig {
@Autowired
Environment environment;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
//传输模式可以设置为epoll也可以设置为nio
config.setTransportMode(TransportMode.NIO);
//集群模式配置
//config.useClusterServers().addNodeAddress(environment.getProperty("redisson.host.config"));
//单节点模式配置
config.useSingleServer().setAddress(environment.getProperty("redisson.host.config")).setKeepAlive(true);
return Redisson.create(config);
}
}
redis的工具类
@Component
public class RedisUtil {
@Autowired
private RedisTemplate redisTemplate;
/**
* 维护一个本类的静态变量
*/
private static RedisUtil redisUtil;
@PostConstruct
public void init() {
redisUtil = this;
redisUtil.redisTemplate = this.redisTemplate;
}
/**
* 将参数中的字符串值设置为键的值,不设置过期时间
*
* @param key
* @param value 必须要实现 Serializable 接口
*/
public static void set(String key, String value) {
redisUtil.redisTemplate.opsForValue().set(key, value);
}
/**
* 将参数中的字符串值设置为键的值,设置过期时间
*
* @param key
* @param value 必须要实现 Serializable 接口
* @param timeout
*/
public static void set(String key, String value, Long timeout) {
redisUtil.redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
/**
* 获取与指定键相关的值
*
* @param key
* @return
*/
public static Object get(String key) {
return redisUtil.redisTemplate.opsForValue().get(key);
}
/**
* 设置某个键的过期时间
*
* @param key 键值
* @param ttl 过期秒数
*/
public static boolean expire(String key, Long ttl) {
return redisUtil.redisTemplate.expire(key, ttl, TimeUnit.SECONDS);
}
/**
* 判断某个键是否存在
*
* @param key 键值
*/
public static boolean hasKey(String key) {
return redisUtil.redisTemplate.hasKey(key);
}
/**
* 向集合添加元素
*
* @param key
* @param value
* @return 返回值为设置成功的value数
*/
public static Long sAdd(String key, String... value) {
return redisUtil.redisTemplate.opsForSet().add(key, value);
}
/**
* 获取集合中的某个元素
*
* @param key
* @return 返回值为redis中键值为key的value的Set集合
*/
public static Set sGetMembers(String key) {
return redisUtil.redisTemplate.opsForSet().members(key);
}
/**
* 将给定分数的指定成员添加到键中存储的排序集合中
*
* @param key
* @param value
* @param score
* @return
*/
public static Boolean zAdd(String key, String value, double score) {
return redisUtil.redisTemplate.opsForZSet().add(key, value, score);
}
/**
* 返回指定排序集中给定成员的分数
*
* @param key
* @param value
* @return
*/
public static Double zScore(String key, String value) {
return redisUtil.redisTemplate.opsForZSet().score(key, value);
}
/**
* 删除指定的键
*
* @param key
* @return
*/
public static Boolean delete(String key) {
return redisUtil.redisTemplate.delete(key);
}
/**
* 删除多个键
*
* @param keys
* @return
*/
public static Long delete(Collection keys) {
return redisUtil.redisTemplate.delete(keys);
}
}
基于redis 实现延迟队列
使用offer 推送到延迟队列(RDelayedQueue), 延迟队列的消息到期后, 会移动至RBlockingQueue(阻塞队列中), 订阅者从阻塞队列中获取消息进行消费
@Component
@Slf4j
public class DelayQueuePublisher {
@Autowired
RedissonClient redissonClient;
public void sendDelayMsg(UserLoginDTO dto, long ttl) {
try {
RBlockingQueue<UserLoginDTO> rBlockingQueue = redissonClient.getBlockingQueue(RedisKeyConstant.REDISSON_DELAY_QUEUE);
RDelayedQueue<UserLoginDTO> rDelayedQueue = redissonClient.getDelayedQueue(rBlockingQueue);
rDelayedQueue.offer(dto, ttl, TimeUnit.SECONDS);
log.info("redisson延迟队列生产者发送消息:{}", dto);
}catch (Exception e) {
log.error(e.getMessage());
}
}
}
@Component
@EnableScheduling
@Slf4j
public class DelayQueueConsumer {
@Autowired
RedissonClient redissonClient;
@Scheduled(cron = "*/1 * * * * ?")
public void consumeMsg() throws InterruptedException {
RBlockingQueue<UserLoginDTO> rBlockingQueue = redissonClient.getBlockingQueue(RedisKeyConstant.REDISSON_DELAY_QUEUE);
UserLoginDTO dto = rBlockingQueue.take();
if(dto!=null) {
log.info("redisson 延迟队列-消息者-收到消息:{}", dto);
}
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
@Slf4j
public class Test1 {
@Autowired
DelayQueuePublisher delayQueuePublisher;
@Test
public void test1() {
RedisUtil.set("testKey1", "testValue");
System.out.println(RedisUtil.get("testKey1"));
}
@Test
public void test2() throws InterruptedException {
UserLoginDTO dto = new UserLoginDTO();
dto.setUserName("zhangsan");
delayQueuePublisher.sendDelayMsg(dto, 2);
Thread.sleep(4000);
}
}
redis 各种数据结构的使用
string:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
@Slf4j
public class StringTest {
@Autowired
RedisTemplate redisTemplate;
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
ObjectMapper objectMapper;
/**
* 使用redisTemplate 操作字符串
*/
@Test
public void test1() {
String key = "redis:template:one:string";
String context = "redisTemplate实战字符串实战";
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, context);
Object result = valueOperations.get(key);
log.info("读出来的内容:{}", result);
}
/**
* 使用redisTemplate 操作对象
*/
@Test
public void test2() throws IOException {
User user = new User(1, "debug", "阿修罗");
ValueOperations valueOperations = redisTemplate.opsForValue();
final String key = "redis:template:two:object";
final String content = objectMapper.writeValueAsString(user);
valueOperations.set(key, content);
Object result = valueOperations.get(key);
if(result!=null) {
User resultUser = objectMapper.readValue(result.toString(), User.class);
log.info("读取缓存并反序列化:{}", resultUser);
}
}
/**
* 使用stringRedisTemplate 操作字符串
*/
@Test
public void test3() {
final String key = "redis:three";
final String content = "StringRedisTemplate实战字符串信息";
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set(key, content);
Object result = valueOperations.get(key);
log.info("读取出来的内容:{}", result);
}
/**
* 使用stringRedisTemplate 操作对象
*/
@Test
public void test4() throws IOException {
final String key = "redis:four";
User user = new User(2, "SteadyJack", "阿修罗");
final String content = objectMapper.writeValueAsString(user);
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set(key, content);
Object result = valueOperations.get(key);
if(result!=null) {
User resultUser = objectMapper.readValue(result.toString(), User.class);
log.info("读取缓存并反序列化:{}", resultUser);
}
}
}
list:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
@Slf4j
public class ListTest {
@Autowired
RedisTemplate redisTemplate;
/**
* 操作列表
*/
@Test
public void test1() {
List<User> list = Arrays.asList(
new User(1, "debug", "修罗"),
new User(2, "jack", "大圣"),
new User(3, "lee", "盘古")
);
final String key = "redis:test:2";
redisTemplate.delete(key);
ListOperations listOperations = redisTemplate.opsForList();
for(User u:list) {
//从队列尾部添加
//1,2,3
listOperations.leftPush(key, u);
}
Object res = listOperations.rightPop(key);
User user;
while (res!=null) {
user = (User) res;
log.info("当前数据:{}", user);
//1, 2, 3
res = listOperations.rightPop(key);
}
}
}
set:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
@Slf4j
public class SetTest {
@Autowired
RedisTemplate redisTemplate;
/**
* 集合-无序,不重复
*/
@Test
public void test1() {
List<String> list = Arrays.asList("debug", "jack", "lee", "debug");
final String key = "redis:test:3";
redisTemplate.delete(key);
SetOperations setOperations = redisTemplate.opsForSet();
for(String str:list) {
setOperations.add(key, str);
}
Object res = setOperations.pop(key);
while (res!=null) {
log.info("从缓存中获取的用户集合-当前用户:{}", res);
res = setOperations.pop(key);
}
}
}
zset:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
@Slf4j
public class ZSetTest {
@Autowired
RedisTemplate redisTemplate;
/**
* ZSet 有序集合
*/
@Test
public void test1() {
List<PhoneUser> list = Arrays.asList(
new PhoneUser("103", 130.0),
new PhoneUser("101", 120.0),
new PhoneUser("102", 80.0)
);
final String key = "redis:test:4";
redisTemplate.delete(key);
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
for(PhoneUser phoneUser:list) {
zSetOperations.add(key, phoneUser, phoneUser.getFare());
}
Long size = zSetOperations.size(key);
//从小到大
//Set<PhoneUser> set = zSetOperations.range(key, 0L, size);
//从大到小
Set<PhoneUser> set = zSetOperations.reverseRange(key, 0L, size);
for(PhoneUser u:set) {
log.info("当前记录:{}", u);
}
}
}
hash:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
@Slf4j
public class HashTest {
@Autowired
RedisTemplate redisTemplate;
/**
* Hash
*/
@Test
public void test1() {
List<Student> students = Arrays.asList(
new Student("10010", "debug", "大圣"),
new Student("10011", "jack", "修罗"),
new Student("10012", "sam", "上古")
);
String key = "redis:test:5";
redisTemplate.delete(key);
HashOperations hashOperations = redisTemplate.opsForHash();
for(Student student:students) {
hashOperations.put(key, student.getId(), student);
}
Map<String, Student> sMap = hashOperations.entries(key);
for(String id:sMap.keySet()) {
log.info("id:{}, student:{}", id, sMap.get(id));
}
String id = "10012";
Student student = (Student) hashOperations.get(key, id);
log.info("指定学生:{}", student);
}
}
布隆过滤器的使用:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ServerProvider.class)
@Slf4j
public class RedissonBloomTest {
@Autowired
RedissonClient redissonClient;
@Test
public void test1() throws IOException {
System.out.println(redissonClient.getConfig().toJSON());
}
/**
* 布隆过滤器-校验基本类型是否存在
*/
@Test
public void test2() {
final String key = "myBloomFilterDataV2";
Long total = 100000L;
//创建布隆过滤器组件
RBloomFilter<Integer> bloomFilter = redissonClient.getBloomFilter(key);
//初始化布隆过滤器, 预计统计元素数量为100000, 期望误差为0.01
bloomFilter.tryInit(total, 0.01);
for(int i=1;i<total;i++) {
bloomFilter.add(i);
}
log.info("该布隆过滤器是否包含数据1:{}"+bloomFilter.contains(1));
log.info("该布隆过滤器是否包含数据-1:{}"+bloomFilter.contains(-1));
log.info("该布隆过滤器是否包含数据1000:{}"+bloomFilter.contains(1000));
}
/**
* 布隆过滤器-校验对象是否存在
*/
@Test
public void test3() {
final String key = "myBloomFilterDataV3";
Long total = 1000L;
//创建布隆过滤器组件
RBloomFilter<BloomDTO> bloomFilter = redissonClient.getBloomFilter(key);
//初始化布隆过滤器, 预计统计元素数量为1000, 期望误差为0.01
bloomFilter.tryInit(total, 0.01);
BloomDTO dto1 = new BloomDTO(1, "1");
BloomDTO dto2 = new BloomDTO(10, "10");
BloomDTO dto3 = new BloomDTO(100, "100");
bloomFilter.add(dto1);
bloomFilter.add(dto2);
bloomFilter.add(dto3);
log.info("该布隆过滤器是否包含数据1:{}"+bloomFilter.contains(new BloomDTO(1, "1")));
log.info("该布隆过滤器是否包含数据10:{}"+bloomFilter.contains(new BloomDTO(10, "10")));
log.info("该布隆过滤器是否包含数据1000:{}"+bloomFilter.contains(new BloomDTO(1000, "1000")));
}
}