谨以此做个笔记。
平时我们使用的redis无非是用作缓存以及分布式session,其他的作用就视项目需求而定了。
这里主要讲讲redis作为缓存的作用。
使用redis做缓存,可以选择单独使用,也可以和spring cache整合。
单独使用redis也很方便,只是代码耦合性高了,所以这次试试与spring cache整合使用。
spring cache主要是代码级的缓存,加上redis可以使代码解耦又可以使缓存以单纯的内存级发挥作用。可能理解不完全对,具体的可以再去深入了解一下,这里谨以此做个笔记而已。
话不多说,开始。
spring boot版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/>
</parent>
1、引入redis和spring cache依赖包,pom.xml文件如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
注:lombok依赖包可以自动生成getter、setter以及构造函数等方法,挺好用的。
2、创建一个简单的POJO
@Data
public class User {
private int id;
private String name;
private int age;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
3、因为这里用的mybatis,所以创建与POJO对应的mapper
@Mapper
public interface UserMapper {
@Insert("INSERT INTO users(name, age) VALUES(#{name}, #{age})")
int save(User user);
@Select("SELECT * FROM users WHERE id = #{id}")
User getById(int id);
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteUser(int id);
@Update("UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id}")
int updateUser(User user);
}
4、创建UserService
public interface UserService {
User getById(int id);
int deleteUser(int id);
int updateUser(int id, User user);
void cleanCache();
}
5、配置application.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 761341
redis:
host: localhost
port: 6379
pool:
max-active: 8
max-idle: 8
max-wait: -1
min-idle: 1
management:
security:
enabled: false
redis-expires:
cache-names: redisCache
default-expiration: 3600
expires:
redisCache: 3600
6、配置RedisCacheManager
@Configuration
@EnableCaching
@EnableConfigurationProperties(RedisProperties.class)
@ConfigurationProperties(prefix = "redis-expires")
public class CustomRedisCacheManager {
@Autowired
private RedisProperties redisProperties;
private List<String> cacheNames;
private long defaultExpiration;
private Map<String, Long> expires;
public List<String> getCacheNames() {
return cacheNames;
}
public void setCacheNames(List<String> cacheName) {
this.cacheNames = cacheName;
}
public long getDefaultExpiration() {
return defaultExpiration;
}
public void setDefaultExpiration(long defaultExpiration) {
this.defaultExpiration = defaultExpiration;
}
public Map<String, Long> getExpires() {
return expires;
}
public void setExpires(Map<String, Long> expires) {
this.expires = expires;
}
/**
* 重写缓存key生成机制
* @return
*/
// @Bean
// @Primary
// public KeyGenerator keyGenerator() {
// return (target, method, params) -> {
// StringBuilder sb = new StringBuilder();
// sb.append(target.getClass().getName());
// sb.append(method.getName());
// for (Object obj : params) {
// sb.append(obj.toString());
// }
// return sb.toString();
// };
// }
@Bean("redisCacheManager")
@Primary
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
cacheManager.setCacheNames(cacheNames);
cacheManager.setDefaultExpiration(defaultExpiration);
cacheManager.setExpires(expires); // 设置缓存过期时间
cacheManager.setUsePrefix(true); // 是否使用缓存前缀
redisTemplate.afterPropertiesSet();
return cacheManager;
}
/**
* 配置json序列化
*/
@Bean
@Primary
public RedisTemplate<Object, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
Jackson2JsonRedisSerializer 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.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(redisProperties.getHost());
jedisConnectionFactory.setPort(redisProperties.getPort());
jedisConnectionFactory.setTimeout(redisProperties.getTimeout());
jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
jedisConnectionFactory.afterPropertiesSet();
return jedisConnectionFactory;
}
private JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
RedisProperties.Pool props = this.redisProperties.getPool();
jedisPoolConfig.setMaxTotal(props.getMaxActive());
jedisPoolConfig.setMaxIdle(props.getMaxIdle());
jedisPoolConfig.setMinIdle(props.getMinIdle());
jedisPoolConfig.setMaxWaitMillis(props.getMaxWait());
return jedisPoolConfig;
}
}
注:KeyGenerator可以配置缓存key的生成策略,如果不配置将使用SimpleKeyGenerator生成key,源码如下,但是建议还是在处理缓存的时候指定key。
public static Object generateKey(Object... params) {
if (params.length == 0) {
return SimpleKey.EMPTY;
}
if (params.length == 1) {
Object param = params[0];
if (param != null && !param.getClass().isArray()) {
return param;
}
}
return new SimpleKey(params);
}
7、实现UserService
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
//这里指定了cacheNames = "redisCache"表示使用我们配置的默认缓存管理器也就是RedisCacheManager。debug模式可以看见第二次查询时不会进入方法体。
@Cacheable(cacheNames = "redisCache", key = "#id")
public User getById(int id) {
return userMapper.getById(id);
}
@Override
@CacheEvict(cacheNames = "redisCache", key = "#id")
public int deleteUser(int id) {
return userMapper.deleteUser(id);
}
@Override
//更新指定缓存
@CachePut(cacheNames = "redisCache", key = "#id")
//清除指定缓存
//@CacheEvict(cacheNames = "redisCache", key = "#id")
public int updateUser(int id, User user) {
user.setId(id);
return userMapper.updateUser(user);
}
@Override
//allEntries = true:清除所有缓存
@CacheEvict(cacheNames = "redisCache", allEntries = true)
public void cleanCache() {
}
}