org.springframework.data.redis.core.ValueOperations#setIfAbsent(K, V, java.time.Duration)
时间: 2023-12-11 11:03:34 浏览: 144
这是一个Redis操作,用于将给定的键值对存储到Redis数据库中。它的作用是仅当指定的key不存在时才设置它的值。如果key已经存在,则此操作不会执行任何操作,也不会更新现有值。
这个方法有三个参数:键,值和过期时间。如果过期时间不为null,则键值对将在指定的时间后过期并从Redis数据库中自动删除。如果过期时间为null,则键值对将永久保存在Redis数据库中。
需要注意的是,这个方法是线程安全的,因为Redis本身是单线程的,所以对Redis的操作都是线程安全的。
相关问题
根据@Override public R<Employee> findById(Integer id) { String key = "ab" + id; //查询缓存 String json = (String) redisTemplate.opsForValue().get(key); if (StrUtil.isNotBlank(json)) { Employee employee = JSONUtil.toBean(json, Employee.class); log.info("从缓存查询id为" + id); return R.success(employee); } //预防缓存穿透 //命中空值 if (json != null) { log.info("缓存命中空值,值不存在"); return R.error("缓存命中空值,值不存在"); } //添加锁 //防止缓存击穿 String lockKey = "s" + id; Employee employee = null; try { //尝试获取锁 boolean b = tryLock(lockKey); //没有获得锁,重试 if (!b) { return findById(id); } //缓存不存在,查询数据库 employee = getById(id); log.info("查询数据库id为" + id); if (employee == null) { //缓存空值解决 缓存穿透 redisTemplate.opsForValue().set(key, "", Duration.ofMinutes(2)); log.info("数据库查值为空"); return R.error("数据库查值为空"); } //添加缓存 redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(employee), Duration.ofSeconds(60)); } catch (Exception e) { throw new RuntimeException(e); } finally { //释放锁 unlock(lockKey); } return R.success(employee); } 用mockito写一个测试方法
好的,以下是使用Mockito编写的测试方法:
```java
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.data.redis.core.RedisTemplate;
class EmployeeServiceTest {
@Mock
private RedisTemplate<String, String> redisTemplate;
private EmployeeService employeeService;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
employeeService = new EmployeeService(redisTemplate);
}
@Test
void testFindByIdFromCache() {
int id = 1;
String key = "ab" + id;
String json = "{\"id\":1,\"name\":\"张三\",\"age\":20}";
Employee employee = new Employee();
employee.setId(id);
employee.setName("张三");
employee.setAge(20);
when(redisTemplate.opsForValue().get(key)).thenReturn(json);
R<Employee> result = employeeService.findById(id);
verify(redisTemplate).opsForValue().get(key);
assertEquals(R.success(employee), result);
}
@Test
void testFindByIdFromDB() {
int id = 1;
String key = "ab" + id;
String lockKey = "s" + id;
String json = null;
Employee employee = new Employee();
employee.setId(id);
employee.setName("张三");
employee.setAge(20);
when(redisTemplate.opsForValue().get(key)).thenReturn(json);
when(redisTemplate.opsForValue().set(key, "{\"id\":1,\"name\":\"张三\",\"age\":20}", Duration.ofSeconds(60))).thenReturn(true);
when(redisTemplate.opsForValue().set(key, "", Duration.ofMinutes(2))).thenReturn(true);
EmployeeService spyEmployeeService = mock(EmployeeService.class);
when(spyEmployeeService.tryLock(lockKey)).thenReturn(true);
when(spyEmployeeService.getById(id)).thenReturn(employee);
R<Employee> result = spyEmployeeService.findById(id);
verify(redisTemplate).opsForValue().get(key);
verify(spyEmployeeService).tryLock(lockKey);
verify(spyEmployeeService).getById(id);
verify(redisTemplate).opsForValue().set(key, "{\"id\":1,\"name\":\"张三\",\"age\":20}", Duration.ofSeconds(60));
assertEquals(R.success(employee), result);
}
}
```
该测试方法使用了`@Mock`注解和`MockitoAnnotations.initMocks(this)`,来创建`RedisTemplate`的Mock对象,并将其注入到`EmployeeService`中。然后,分别编写了两个测试用例,分别测试了从缓存中获取数据和从数据库中获取数据的情况。其中,对于从数据库中获取数据的情况,使用了`Mockito.spy()`方法,来创建`EmployeeService`的Spy对象,以便可以在测试中模拟`tryLock`和`getById`方法的行为。最后,使用`verify()`方法来验证Mock对象的方法是否被调用,使用`assertEquals()`方法来断言方法返回值是否符合预期。
springboot使用redis中的lru
Spring Boot 中可以使用 Spring Data Redis 或 Jedis 等库来操作 Redis,并利用其内置的 LRU (Least Recently Used) 算法来管理缓存数据。当 Redis 的缓存空间达到预设容量时,LRU 就会自动移除最久未使用的条目,以便腾出空间存储新的数据。
具体配置和使用步骤如下:
1. 添加依赖:在 `pom.xml` 文件中添加 Spring Data Redis 或 Jedis 的依赖。
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
```
或者
```xml
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
```
2. 配置 Redis:在 `application.properties` 或 `application.yml` 中配置 Redis 的连接信息。
```properties
spring.redis.host=localhost
spring.redis.port=6379
```
3. 使用 LRU 缓存:Spring Data Redis 提供了 `@Cacheable` 注解来标记缓存方法,如果使用 RedisTemplate 直接操作,可以设置 KeyGenerator 来指定基于哪个属性生成 LRU 删除键。
例如:
```java
import org.springframework.data.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
@Service
public class MyService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 使用 Cacheable 注解并设置 keyGenerator 为 LRU
@Cacheable(value = "myCache", key = "#id", cacheManager = "cacheManager", condition = "#id > 0")
public String getData(int id) {
// 获取数据逻辑...
}
// 另外,如果你使用的是 Spring Data Redis,可以配置缓存管理器
@Bean
public CachingRedisTemplate cachingRedisTemplate(RedisConnectionFactory factory) {
CachingRedisTemplate template = new CachingRedisTemplate(factory);
// 设置 LRU 超过一定大小后开始淘汰缓存
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(5))
.disableCachingNullValues()
.accessCacheEnabled(true)
.evictionPolicy(LRUPolicy.class);
template.setCacheConfigurations(Collections.singletonMap("myCache", config));
return template;
}
}
```
阅读全文