1. 简介

当我们对redis的基本知识有一定的了解后,我们再通过实战的角度学习一下在SpringBoot环境下,如何优雅的使用redis。

我们通过使用SpringBoot内置的Redis注解(文章最后有解释)来操作User相关的信息,

再通过Redis工具类的方式操作Role相关信息来全面的学习Redis的使用。

嫌篇幅太长的 可以直接跳到2.6查看具体逻辑即可。

2. 开撸

2.1 项目结构

结构说明:

├── src
│   └── main
│   ├── java
│   │   └── com
│   │   └── ldx
│   │   └── redis
│   │   ├── RedisApplication.java # 启动类
│   │   ├── config
│   │   │   └── RedisConfig.java # redis 配置类
│   │   ├── constant
│   │   │   └── CacheConstant.java # 缓存key常量类
│   │   ├── controller
│   │   │   ├── RoleController.java # 角色管理控制器
│   │   │   └── UserController.java # 用户管理控制器
│   │   ├── entity
│   │   │   ├── SysRole.java # 角色entity
│   │   │   └── SysUser.java # 用户entity
│   │   ├── mapper
│   │   │   ├── SysRoleMapper.java # 角色持久层
│   │   │   └── SysUserMapper.java # 用户持久层
│   │   ├── service
│   │   │   ├── SysRoleService.java # 角色接口层
│   │   │   ├── SysUserService.java # 用户接口层
│   │   │   └── impl
│   │   │   ├── SysRoleServiceImpl.java # 角色接口实现层
│   │   │   └── SysUserServiceImpl.java # 用户接口实现层
│   │   └── util
│   │   └── RedisUtil.java # redis 工具类
│   └── resources
│   └── application.yaml # 系统配置文件
└── pom.xml # 依赖管理

2.2 导入依赖

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ldx</groupId>
<artifactId>redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--spring-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce pool -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok 工具包 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

2.3 项目基本配置

2.3.1 application.yaml

spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 123456
type: com.zaxxer.hikari.HikariDataSource
# redis 配置
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms mybatis-plus:
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mapper-locations: classpath*:mapper/*.xml
# 设置别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.ldx.redis.entity
configuration:
# 控制台sql打印
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志配置
logging:
level:
com.ldx.redis.service.impl: debug
org.springframework: warn

2.3.2 启动类

@EnableCaching:激活缓存支持

@MapperScan: 扫描mapper接口层

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching; /**
* 启动类
* @author ludangxin
* @date 2021/8/11
*/
@EnableCaching
@MapperScan(basePackages = "com.ldx.redis.mapper")
@SpringBootApplication
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}

2.4 redis配置

2.4.1 RedisConfig

我们除了在application.yaml中加入redis的基本配置外,一般还需要配置redis key和value的序列化方式,如下:

注解:

  1. 其默认的序列化方式为JdkSerializationRedisSerializer,这种方式跨语言和可读性都不太好,我们将其切换为Jackson2JsonRedisSerializer

  2. 可以使用entryTtl()为对应的模块设置过期时长。

redisTemplate:参考redisTemplate()

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ldx.redis.constant.CacheConstant;
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.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map; /**
* redis配置类
* @author ludangxin
* @date 2021/8/11
*/
@Configuration
public class RedisConfig { @Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
//设置不同cacheName的过期时间
Map<String, RedisCacheConfiguration> configurations = new HashMap<>(16);
// 序列化方式
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = getJsonRedisSerializer();
RedisSerializationContext.SerializationPair<Object> serializationPair =
RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer);
// 默认的缓存时间
Duration defaultTtl = Duration.ofSeconds(20L);
// 用户模块的缓存时间
Duration userTtl = Duration.ofSeconds(50L);
// 默认的缓存配置
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
//.entryTtl(defaultTtl)
.serializeValuesWith(serializationPair);
// 自定义用户模块的缓存配置 自定义的配置可以覆盖默认配置(当前的模块)
configurations.put(CacheConstant.USER_CACHE_NAME, RedisCacheConfiguration.defaultCacheConfig()
//.entryTtl(userTtl)
.serializeValuesWith(serializationPair)
); return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory))
.cacheDefaults(redisCacheConfiguration)
.withInitialCacheConfigurations(configurations)
// 事物支持
.transactionAware()
.build();
} @Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = getJsonRedisSerializer();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jsonRedisSerializer);
// 支持事物
//template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
} /**
* 设置jackson的序列化方式
*/
private Jackson2JsonRedisSerializer<Object> getJsonRedisSerializer() {
Jackson2JsonRedisSerializer<Object> redisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
redisSerializer.setObjectMapper(om);
return redisSerializer;
}
}

2.4.1 CacheConstant

我们为了防止redis中key的重复,尽量会给不同的数据主体加上不同的前缀,这样我们在查看和统计的时候也方便操作。

/**
* 缓存key 常量类
* @author ludangxin
* @date 2021/8/11
*/
public interface CacheConstant {
/**
* 用户cache name
*/
String USER_CACHE_NAME = "user_cache"; /**
* 用户信息缓存key前缀
*/
String USER_CACHE_KEY_PREFIX = "user_"; /**
* 角色cache name
*/
String ROLE_CACHE_NAME = "role_cache"; /**
* 角色信息缓存key前缀
*/
String ROLE_CACHE_KEY_PREFIX = "role_"; /**
* 获取角色cache key
* @param suffix 后缀
* @return key
*/
static String getRoleCacheKey(String suffix) {
return ROLE_CACHE_NAME + "::" + ROLE_CACHE_KEY_PREFIX + suffix;
}
}

2.4.2 RedisUtil

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.TimeUnit; /**
* spring redis 工具类
* @author ludangxin
**/
@Component
@RequiredArgsConstructor
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public class RedisUtil {
public final RedisTemplate redisTemplate; /**
* 缓存基本的对象,Integer、String、实体类等
* @param key 缓存的键值
* @param value 缓存的值
* @return 缓存的对象
*/
public <T> ValueOperations<String, T> setCacheObject(String key, T value) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
operation.set(key, value);
return operation;
} /**
* 缓存基本的对象,Integer、String、实体类等
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
* @return 缓存的对象
*/
public <T> ValueOperations<String, T> setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
operation.set(key, value, timeout, timeUnit);
return operation;
} /**
* 获得缓存的基本对象。
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
} /**
* 删除单个对象
* @param key
*/
public void deleteObject(String key) {
redisTemplate.delete(key);
} /**
* 删除集合对象
* @param collection
*/
public void deleteObject(Collection collection) {
redisTemplate.delete(collection);
} /**
* 缓存List数据
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> ListOperations<String, T> setCacheList(String key, List<T> dataList) {
ListOperations listOperation = redisTemplate.opsForList();
if (null != dataList) {
int size = dataList.size();
for (int i = 0; i < size; i++) {
listOperation.leftPush(key, dataList.get(i));
}
}
return listOperation;
} /**
* 获得缓存的list对象
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheList(String key) {
List<T> dataList = new ArrayList<T>();
ListOperations<String, T> listOperation = redisTemplate.opsForList();
Long size = listOperation.size(key);
for (int i = 0; i < size; i++) {
dataList.add(listOperation.index(key, i));
}
return dataList;
} /**
* 缓存Set
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> dataSet) {
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
Iterator<T> it = dataSet.iterator();
while (it.hasNext()) {
setOperation.add(it.next());
}
return setOperation;
} /**
* 获得缓存的set
* @param key
* @return
*/
public <T> Set<T> getCacheSet(String key) {
Set<T> dataSet = new HashSet<T>();
BoundSetOperations<String, T> operation = redisTemplate.boundSetOps(key);
dataSet = operation.members();
return dataSet;
} /**
* 缓存Map
* @param key
* @param dataMap
* @return
*/
public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> dataMap) {
HashOperations hashOperations = redisTemplate.opsForHash();
if (null != dataMap) {
for (Map.Entry<String, T> entry : dataMap.entrySet()) {
hashOperations.put(key, entry.getKey(), entry.getValue());
}
}
return hashOperations;
} /**
* 获得缓存的Map
* @param key
* @return
*/
public <T> Map<String, T> getCacheMap(String key) {
Map<String, T> map = redisTemplate.opsForHash().entries(key);
return map;
} /**
* 获得缓存的基本对象列表
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(String pattern) {
return redisTemplate.keys(pattern);
}
}

2.5 controller

2.5.1 UserController

import com.ldx.redis.entity.SysUser;
import com.ldx.redis.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List; /**
* 用户管理
* @author ludangxin
* @date 2021/8/11
*/
@RestController
@RequestMapping("user")
@RequiredArgsConstructor
public class UserController {
private final SysUserService userService; @GetMapping
public List<SysUser> queryAll() {
return userService.queryAll();
} @GetMapping("{userId}")
public SysUser getUserInfo(@PathVariable Long userId) {
return userService.getUserInfo(userId);
} @PostMapping
public String add(@RequestBody SysUser user) {
userService.add(user);
return "新增成功~";
} @PutMapping("{userId}")
public String update(@PathVariable Long userId, @RequestBody SysUser user) {
userService.update(userId, user);
return "更新成功~";
} @DeleteMapping("{userId}")
public String del(@PathVariable Long userId) {
userService.delete(userId);
return "删除成功~";
}
}

2.5.2 RoleController

import com.ldx.redis.entity.SysRole;
import com.ldx.redis.service.SysRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List; /**
* 角色管理
* @author ludangxin
* @date 2021/8/12
*/
@RestController
@RequestMapping("role")
@RequiredArgsConstructor
public class RoleController {
private final SysRoleService roleService; @GetMapping
public List<SysRole> queryAll() {
return roleService.queryAll();
} @GetMapping("{roleId}")
public SysRole getUserInfo(@PathVariable Long roleId) {
return roleService.getRoleInfo(roleId);
} @PostMapping
public String add(@RequestBody SysRole role) {
roleService.add(role);
return "新增成功~";
} @PutMapping("{roleId}")
public String update(@PathVariable Long roleId, @RequestBody SysRole role) {
roleService.update(roleId, role);
return "更新成功~";
} @DeleteMapping("{roleId}")
public String del(@PathVariable Long roleId) {
roleService.delete(roleId);
return "删除成功~";
}
}

2.6 service.impl

2.6.1 UserServiceImpl

优雅的使用redis注解实现对数据的缓存

@Cacheable:unless:当unless成立时则不缓存。这里判断size主要是不想将空值存入redis。

CacheConstant.USER_CACHE_KEY_PREFIX + "' + #userId":其key = 指定前缀 + 当前方法实参(userId)。

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ldx.redis.constant.CacheConstant;
import com.ldx.redis.entity.SysUser;
import com.ldx.redis.mapper.SysUserMapper;
import com.ldx.redis.service.SysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import java.util.List; /**
* 用户管理实现
* @author ludangxin
* @date 2021/8/11
*/
@Slf4j
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = CacheConstant.USER_CACHE_NAME)
public class SysUserServiceImpl implements SysUserService {
private final SysUserMapper userMapper; @Override
@Cacheable(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'", unless = "#result.size() == 0")
public List<SysUser> queryAll() {
log.debug("查询全部用户信息~");
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
return userMapper.selectList(queryWrapper);
} @Override
@Cacheable(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "' + #userId", unless = "#result == null")
public SysUser getUserInfo(Long userId) {
log.debug("查询用户:{} 详情", userId);
return userMapper.selectById(userId);
} @Override
@CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'")
public void add(SysUser user) {
log.debug("新增用户:{}", user.getNickName());
userMapper.insert(user);
} @Override
@Caching(evict = {@CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'"),
@CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "' + #userId")
})
public void update(Long userId, SysUser user) {
log.debug("更新用户:{}", user.getNickName());
user.setId(userId);
userMapper.updateById(user);
} @Override
@Caching(evict = {@CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "all'"),
@CacheEvict(key = "'" + CacheConstant.USER_CACHE_KEY_PREFIX + "' + #userId")
})
public void delete(Long userId) {
log.debug("删除用户:{}", userId);
userMapper.deleteById(userId);
}
}

2.6.2 SysRoleServiceImpl

使用redis工具类实现对数据的缓存。

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ldx.redis.constant.CacheConstant;
import com.ldx.redis.entity.SysRole;
import com.ldx.redis.mapper.SysRoleMapper;
import com.ldx.redis.service.SysRoleService;
import com.ldx.redis.util.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Collections;
import java.util.List;
import java.util.Objects; /**
* 角色管理
* @author ludangxin
* @date 2021/8/11
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl implements SysRoleService {
private final SysRoleMapper roleMapper; private final RedisUtil redisUtil; String allKey = CacheConstant.getRoleCacheKey("all"); @Override
public List<SysRole> queryAll() {
List<SysRole> roles = redisUtil.getCacheList(allKey);
if(!CollectionUtils.isEmpty(roles)) {
return roles;
}
log.debug("查询全部角色信息~");
LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
List<SysRole> sysRoles = roleMapper.selectList(queryWrapper);
if(CollectionUtils.isEmpty(sysRoles)) {
return Collections.emptyList();
}
redisUtil.setCacheList(allKey, sysRoles);
return sysRoles;
} @Override
public SysRole getRoleInfo(Long roleId) {
String roleCacheKey = CacheConstant.getRoleCacheKey(String.valueOf(roleId));
SysRole role = redisUtil.getCacheObject(roleCacheKey); if(Objects.nonNull(role)) {
return role;
}
log.debug("查询角色:{} 详情", roleId);
SysRole sysRole = roleMapper.selectById(roleId); if(Objects.isNull(sysRole)) {
return null;
}
redisUtil.setCacheObject(roleCacheKey, sysRole);
return sysRole;
} @Override
public void add(SysRole role) {
log.debug("新增角色:{}", role.getName());
roleMapper.insert(role);
redisUtil.deleteObject(allKey);
} @Override
public void update(Long roleId, SysRole role) {
log.debug("更新角色:{}", role.getName());
String roleCacheKey = CacheConstant.getRoleCacheKey(String.valueOf(roleId));
role.setId(roleId);
roleMapper.updateById(role);
// 更新缓存
redisUtil.setCacheObject(roleCacheKey,role);
// 清除缓存
redisUtil.deleteObject(allKey);
} @Override
public void delete(Long roleId) {
log.debug("删除角色:{}", roleId);
roleMapper.deleteById(roleId);
// 清除缓存
redisUtil.deleteObject(CacheConstant.getRoleCacheKey(String.valueOf(roleId)));
redisUtil.deleteObject(allKey); }
}

2.7 启动测试

这里只测试了user模块(都测试并且贴图会显得篇幅太长且繁琐),role模块本人测试后结果正确。

查询列表:

​ 调用接口返回全部数据并缓存完成,再次调用无查询日志输出,符合预期。

​ 接口调用:

​ 查看缓存:

查看用户详情:

​ 接口调用返回用户详情信息并缓存完成,再次调用无查询日志输出,符合预期。

​ 接口调用:

​ 查看缓存:

更新数据:

​ 接口调用返回更新成功,并且查看全部的缓存被清除。符合预期。

​ 接口调用:

​ 查看缓存:

3. 内置缓存注解

3.1 @CacheConfig

@Cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完 那就省事了, 所以,有了@CacheConfig这个配置,@CacheConfig is a class-level annotation that allows to share the cache names,如果你在你的方法写别的名字,那么依然以方法的名字为准。

3.2 @Cacheable

@Cacheable(value="myCache"),这个注释的意思是,当调用这个方法的时候,会从一个名叫myCache 的缓存中查询,如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中,否则返回缓存中的对象。

3.3 @CachePut

@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用。

3.4 @CacheEvict

@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空。

// 清空当前cache name下的所有key
@CachEvict(allEntries = true)

3.5 @Caching

@Caching可以使注解组合使用,比如根据id查询用户信息,查询完的结果为{key = id,value = userInfo},但我们现在为了方遍,想用用户的手机号,邮箱等缓存对应用户的信息,这时候我们就要使用@Caching。例:

@Caching(put = {
@CachePut(value = "user", key = "#user.id"),
@CachePut(value = "user", key = "#user.username"),
@CachePut(value = "user", key = "#user.email")
})
public User getUserInfo(User user){
...
return user;
}

Redis实战-详细配置-优雅的使用Redis注解/RedisTemplate的更多相关文章

  1. Redis实战总结-配置、持久化、复制

    Redis的配置主要放置在redis.conf,可以通过修改配置文件实现Redis许多特性,比如复制,持久化,集群等. redis.conf部分配置详解 # 启动redis,显示加载配置redis.c ...

  2. 小D课堂 - 零基础入门SpringBoot2.X到实战_第9节 SpringBoot2.x整合Redis实战_39、SpringBoot2.x整合redis实战讲解

    笔记 3.SpringBoot2.x整合redis实战讲解 简介:使用springboot-starter整合reids实战 1.官网:https://docs.spring.io/spring-bo ...

  3. Redis实战篇(一)搭建Redis实例

    今天是Redis实战系列的第一讲,先从如何搭建一个Redis实例开始. 下面介绍如何在Docker.Windows.Linux下安装. Docker下安装 1.查看可用的 Redis 版本 访问 Re ...

  4. Redis实战阅读笔记——第二章(redis重构web)

    在性能的要求下,如何用redis重构已有的已有的部分,其实整个例子背后的思路挺好的.在应用缓存的过程中,还有一指标个需要考虑,读写比.

  5. Redis实战总结-Redis的高可用性

    在之前的博客<Redis实战总结-配置.持久化.复制>给出了一种Redis主从复制机制,简单地实现了Redis高可用.然后,如果Master服务器宕机,会导致整个Redis瘫痪,这种方式的 ...

  6. redis的主从复制配置

    redis的主从复制配置 一.     原理 Redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架 ...

  7. 【转载】Redis Sentinel服务配置

    转载地址:http://blog.csdn.net/vtopqx/article/details/49247285 redis官网文档:http://www.redis.cn/topics/senti ...

  8. Spring集成Redis集群(含spring集成redis代码)

    代码地址如下:http://www.demodashi.com/demo/11458.html 一.准备工作 安装 Redis 集群 安装参考: http://blog.csdn.net/zk6738 ...

  9. 在centos7中安装redis,并通过node.js操作redis

    引言 最近在学习node.js 连接redis的模块,所以尝试了一下在虚拟机中安装cent OS7,并安装redis,并使用node.js 操作redis.所以顺便做个笔记. 如有不对的地方,欢迎大家 ...

随机推荐

  1. 22、部署drdb

    22.1.heartbeat部署规划: 本文的实验环境是虚拟机设备: 名称 接口 ip 用途 master-db(主) eth0 10.0.0.16/24 用于服务器之间的数据同步(直连) eth1 ...

  2. keycloak~自定义SPI的注入与扩展

    项目结构 自定义SPI注册 1. 直接复制文件方式 docker cp keycloak-service-self-spi.jar keycloak:/opt/ docker cp module-on ...

  3. POJ 2084 Game of Connections 卡特兰数

    看了下大牛们的,原来这题是卡特兰数,顺便练练java.递归式子:h(0)=1,h(1)=1   h(n)= h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)h(0) ( ...

  4. Luogu P4553 80人环游世界

    link 题目大意 自东向西有 \(n\) 个国家.有 \(m\) 个人,他们可以选择 \(n\) 个国家中任意一个开始,任意一个结束,但路线必须自东向西,且第 \(i\) 个国家必须恰好经过 \(v ...

  5. python 16篇 多线程和多进程

    1.概念 线程.进程 进程 一个程序,它是一组资源的集合 一个进程里面默认是有一个线程的,主线程 多进程是可以利用多核cpu的线程 最小的执行单位 线程和线程之间是互相独立的 主线程等待子线程执行结束 ...

  6. 痞子衡嵌入式:嵌入式Cortex-M裸机环境下临界区保护的三种实现

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是Cortex-M裸机环境下临界区保护的三种实现. 搞嵌入式玩过 RTOS 的朋友想必都对 OS_ENTER_CRITICAL().OS_ ...

  7. Cesium加载地形数据只显示半个地球

    Cesium第0级地形包括两个瓦片:0/0/0.terrain,0/1/0.terrain,分别为左半球和右半球(具体参考:https://blog.csdn.net/u013929284/artic ...

  8. 第二篇 -- Go语言转义字符与变量声明

    上节我们讲了GO语言的环境搭建以及创建了Hello World程序.今天学习一下Go语言基础语法 开发前准备 1. 首先创建一个Project02 2. 在Project02下面新建一个test1.g ...

  9. 利用C++11可变模板,封装调用dll导出函数

    起因 开发中经常需要动态调用一些导出函数,试着利用C++11特性封装一下 尝试 常规使用 typedef int WINAPI (*TMessageBoxA)(HWND hWnd,LPCSTR lpT ...

  10. 深入刨析tomcat 之---第4篇 tomcat4.0连接池 实现原理

    writedby 张艳涛