如何使用 StringRedisTemplate 操作 Redis 详解
Redis 简介
Redis 是一个开源(BSD 许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。支持事务 5.0 版本新增 stream 数据类型。
Spring boot 单数据源配置
Springboot 的 redis 单数据源配置特别简单
(1)配置 appliation.properties 文件
spring.redis.host=x.x.x.x
spring.redis.port=6379
#redis 的数据库号
spring.redis.database=4
spring.redis.timeout = 30000ms
spring.redis.jedis.pool.max-active=200
spring.redis.jedis.pool.max-idle=0
spring.redis.lettuce.pool.max-idle=5
spring.redis.jedis.pool.max-wait=20000ms
(2)StringRedisTemplate 的基本操作
StringRedisTemplate 自动关闭 redis 连接
// 注入对象
@Autowired
private StringRedisTemplate stringRedisTemplate;
#获取 ValueOperations 操作 String 数据
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set("strRedis","StringRedisTemplate");
valueOperations.get("strRedis");
#设置过期时间
set("timeStep", new Date().getTime()+"", 2 ,TimeUnit.MINUTES);
#获取 SetOperations 操作 Set 数据
SetOperations<String, String> set = stringRedisTemplate.opsForSet();
set.add("set1","22");
set.add("set1","33");
set.add("set1","44");
Set<String> resultSet =stringRedisTemplate.opsForSet().members("set1");
stringRedisTemplate.opsForSet().add("set2", "1","2","3");// 向指定 key 中存放 set 集合
Set<String> resultSet1 =stringRedisTemplate.opsForSet().members("set2");
log.info("resultSet:"+resultSet);
log.info("resultSet1:"+resultSet1);
#获取 ListOperations 操作 List 数据,list 可以用来实现队列。// 将数据添加到 key 对应的现有数据的左边
Long redisList = stringRedisTemplate.opsForList().leftPush("redisList", "3");
stringRedisTemplate.opsForList().leftPush("redisList", "4");
// 将数据添加到 key 对应的现有数据的右边
Long size = stringRedisTemplate.opsForList().size("redisList");
// 从左往右遍历
String leftPop = stringRedisTemplate.opsForList().leftPop("redisList");
// 从右往左遍历
String rightPop = stringRedisTemplate.opsForList().rightPop("redisList");
// 查询全部元素
List<String> range = stringRedisTemplate.opsForList().range("redisList", 0, -1);
// 查询前三个元素
List<String> range1 = stringRedisTemplate.opsForList().range("redisList", 0, 3);
// 从左往右删除 list 中元素 A (1: 从左往右 -1: 从右往左 0: 删除全部)
Long remove = stringRedisTemplate.opsForList().remove("key", 1, "A");
log.info("redisList----"+redisList);
log.info("size----"+size);
log.info("leftPop----"+leftPop);
log.info("rightPop----"+rightPop);
log.info("range----"+range);
log.info("range1----"+range1);
log.info("remove----"+remove);
// 判断 key 对应的 map 中是否存在 hash
Boolean aBoolean = stringRedisTemplate.opsForHash().hasKey("hash", "hash1");
// 往 key 对应的 map 中新增 (key1,value1)
stringRedisTemplate.opsForHash().put("hash", "hash1", "value1");
// 获取 key 对应的 map 中 hash1 的值
Object o = stringRedisTemplate.opsForHash().get("hash", "hash1");
// 删除 key 对应的 map 中多个子 hash(可变参数)
Long delete = stringRedisTemplate.opsForHash().delete("hash", "key1", "key2", "key3");
// 获取 hash 对应的 map
Map<Object, Object> hash = stringRedisTemplate.opsForHash().entries("hash");
// 获取 hash 对应的 map 中全部子 hash 集合
Set<Object> hash1 = stringRedisTemplate.opsForHash().keys("hash");
// 获取 hash 对应的 map 中全部 value 集合
List<Object> hash2 = stringRedisTemplate.opsForHash().values("hash");
#删除键
Boolean key = stringRedisTemplate.delete("key");
#数字加 x
Long count = stringRedisTemplate.boundValueOps("count").increment(1);//val +1
#获取过期时间,不设的话为 -1
Long time = stringRedisTemplate.getExpire("count")
Spring boot 多数据源配置, 配置一个 1 号库,一个 4 号库
添加依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
修改 application.properties 配置文件
#1 号库
spring.redis.redis-onedb.database=0
spring.redis.redis-onedb.hostName=192.168.90.42
spring.redis.redis-onedb.port=9110
spring.redis.redis-onedb.timeout=5000
#4 号库
spring.redis.redis-fourdb.database=4
spring.redis.redis-fourdb.hostName=192.168.90.42
spring.redis.redis-fourdb.port=9110
spring.redis.redis-fourdb.timeout=5000
创建 RedisConfig.java 文件
@Configuration
public class RedisConfig {
@Bean
@ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
@Scope(value = "prototype")
public GenericObjectPoolConfig redisPool(){return new GenericObjectPoolConfig();
}
@Bean
@ConfigurationProperties(prefix = "spring.redis.redis-fourdb")
public RedisStandaloneConfiguration redisConfigA(){return new RedisStandaloneConfiguration();
}
@Bean
@ConfigurationProperties(prefix = "spring.redis.redis-onedb")
public RedisStandaloneConfiguration redisConfigB(){return new RedisStandaloneConfiguration();
}
@Primary
@Bean
public LettuceConnectionFactory factoryA(GenericObjectPoolConfig config, RedisStandaloneConfiguration redisConfigA){LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder()
.poolConfig(config).commandTimeout(Duration.ofMillis(config.getMaxWaitMillis())).build();
return new LettuceConnectionFactory(redisConfigA, clientConfiguration);
}
@Bean
public LettuceConnectionFactory factoryB(GenericObjectPoolConfig config, RedisStandaloneConfiguration redisConfigB){LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder()
.poolConfig(config).commandTimeout(Duration.ofMillis(config.getMaxWaitMillis())).build();
return new LettuceConnectionFactory(redisConfigB, clientConfiguration);
}
@Bean(name = "fourRedis")
public StringRedisTemplate redisBusTemplate(@Qualifier("factoryA") LettuceConnectionFactory factoryA){StringRedisTemplate template = getRedisTemplate();
template.setConnectionFactory(factoryA);
return template;
}
@Bean(name = "oneRedis")
public StringRedisTemplate redisLoginTemplate(@Qualifier("factoryB")LettuceConnectionFactory factoryB){StringRedisTemplate template = getRedisTemplate();
template.setConnectionFactory(factoryB);
return template;
}
private StringRedisTemplate getRedisTemplate(){StringRedisTemplate template = new StringRedisTemplate();
template.setValueSerializer(new GenericFastJsonRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
}
在需要使用的类,注入就可以使用
@Resource(name = "oneRedis")
private StringRedisTemplate oneRedis;
@Resource(name = "fourRedis")
private StringRedisTemplate fourRedis;
StringRedisTemplate 实现事务
stringRedisTemplate.setEnableTransactionSupport(true);
try {stringRedisTemplate.multi();// 开启事务
stringRedisTemplate.opsForValue().increment("count", 1);
stringRedisTemplate.opsForValue().increment("count1", 2);
// 提交
stringRedisTemplate.exec();}catch (Exception e){log.error(e.getMessage(), e);
// 开启回滚
stringRedisTemplate.discard();}
注意:StringRedisTemplate 开启事务之后,不释放连接。如果我们使用 Spring 事务管理不存在这个问题
StringRedisTemplate 实现乐观锁
redisTemplate.watch("key"); // 1
redisTemplate.multi();
redisTemplate.boundValueOps("key").set(""+id);
List<Object> list= redisTemplate.exec();
System.out.println(list);
if(list != null){
// 操作成功
System.out.println(id+"操作成功");
}else{
// 操作失败
System.out.println(id+"操作失败");
}
StringRedisTemplate 实现 pipe 管道
StringRedisTemplate 实现分布式锁
String lockKey = "key";
String lockValue = lockKey+System.currentTimeMillis();
// value 需要记住用于解锁
while (true){Boolean ifPresent = stringRedisTemplate.opsForValue().
setIfAbsent("redis-lock:" + lockKey, lockValue, 3, TimeUnit.SECONDS);
if (ifPresent){log.info("get redis-lock success");
break;
}
}
// 解锁
String lockKey = "key";
String lockValue = lockKey + System.currentTimeMillis();
boolean result = false;
// value 需要记住用于解锁
stringRedisTemplate.watch("redis-lock:" + lockKey);
String value = stringRedisTemplate.opsForValue().get("redis-lock:" + lockKey);
if (null == value){result = true;}else if (value.equals(lockValue)) {stringRedisTemplate.delete("redis-lock:" + lockKey);
result = true;
}
stringRedisTemplate.unwatch();
Redis 缓存击穿、穿透和雪崩
缓存击穿,是指一个 key 非常热点,在不停的扛着大并发,大并发集中对这一个点进
行访问,当这个 key 在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就
像在一个屏障上凿开了一个洞
缓存穿透,是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果 key 不存在或者 key 已经过期,再对数据库进行查
询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。解决办法是即使查出的对象为空,也放入缓存时间设短一点。缓存雪崩,是指在某一个时间段,缓存集中过期失效。
有问题,请留言!
个人博客地址 王开金的博客