配置
pom依赖
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- jedis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2,使用jedis必须依赖它-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
配置文件
# 数据苦索引(默认0)
spring.redis.database=0
spring.redis.host=
spring.redis.port=6379
spring.redis.password=
# 最大连接数
spring.redis.jedis.pool.max-active=8
# 最大阻塞时间
spring.redis.jedis.pool.max-wait=5000ms
# 最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间
spring.redis.timeout=50000ms
测试
测试代码
这里只展示最核心的代码片段,完整代码可以进入项目查看
service
import com.ouyanglol.demo.dao.UserDAO;
import com.ouyanglol.demo.model.User;
import com.ouyanglol.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* @author Ouyang
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Autowired
private RedisTemplate redisTemplate;
@Override
public User selectById(String id) {
//首次查询redis数据库有无缓存,没有就从数据库查,并把查到的数据放入redis缓存
if (redisTemplate.opsForValue().get(id)==null) {
User user = userDAO.selectByPrimaryKey(id);
redisTemplate.opsForValue().set(id,user);
return user;
}
return (User)redisTemplate.opsForValue().get(id);
}
}
controller
import com.ouyanglol.demo.model.User;
import com.ouyanglol.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Ouyang
*/
@RestController
@RequestMapping("user")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public String get(@PathVariable(name = "id") String id) {
log.info("id-->{}",id);
User user = userService.selectById(id);
log.info("user-->{}",user);
return user.toString();
}
}
test
public class UserControllerTest extends DemoApplicationTests {
@Autowired
private UserController userController;
@Test
public void get() {
assertNotNull(userController.get("12"));
}
}
测试结果
初次执行
可以看出,第一次有执行sql
语句,说明redis
没有查到数据。
第二次执行
第二次没有sql
语句的打印,说明直接从redis
获取了数据,并且user
内容和数据库直接读取的内容一样。
优化使用
序列化
如果只做如上配置,其实仅仅是能使用RedisTemplate
而已,如果直接进入数据库查看刚才插入的数据,只是一堆乱码而已。
添加fastjson依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
个人比较喜欢使用fastjson
,如果不想依赖三方包,也可以使用Jackson2JsonRedisSerializer
代替FastJsonRedisSerializer
新增config类
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import java.time.Duration;
import org.springframework.cache.CacheManager;
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.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author Ouyang
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
//使用fastjson序列化
GenericFastJsonRedisSerializer jsonRedisSerializer = new GenericFastJsonRedisSerializer();
// Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//解决Jackson2JsonRedisSerializer配置序列化(解决乱码的问题)
// ObjectMapper om = new ObjectMapper();
// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// jsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
//value序列化
template.setValueSerializer(jsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jsonRedisSerializer);
return template;
}
/**
* 默认保存30秒
* @param factory RedisConnectionFactory
* @return CacheManager
*/
@Bean
@Primary
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
//使用fastjson序列化
GenericFastJsonRedisSerializer jsonRedisSerializer = new GenericFastJsonRedisSerializer();
//解决查询缓存转换异常的问题
// Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//解决Jackson2JsonRedisSerializer配置序列化(解决乱码的问题)
// ObjectMapper om = new ObjectMapper();
// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// jsonRedisSerializer.setObjectMapper(om);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(30))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer))
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
/**
* 保存一个月
* @param factory RedisConnectionFactory
* @return CacheManager
*/
@Bean("month")
public CacheManager cacheManagerForMonth(RedisConnectionFactory factory) {
RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
//使用fastjson序列化
GenericFastJsonRedisSerializer jsonRedisSerializer = new GenericFastJsonRedisSerializer();
// Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//解决Jackson2JsonRedisSerializer配置序列化(解决乱码的问题)
// ObjectMapper om = new ObjectMapper();
// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// jsonRedisSerializer.setObjectMapper(om);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(30))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer))
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}
使用注释
service
package com.ouyanglol.demo.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ouyanglol.demo.dao.UserDAO;
import com.ouyanglol.demo.model.User;
import com.ouyanglol.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* @author Ouyang
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
@Cacheable(value = "user",key = "#id")
public User selectByIdV2(String id) {
return userDAO.selectByPrimaryKey(id);
}
}
使用@Cacheable
的方法,会根据value
和key
的值,对缓存的key进行查找,如果能找到,则不进入方法内部,直接返回缓存数据,比自己手动使用redisTemplate
方便许多。
自己可以设定多个CacheManager
(比如每个manager过期时间不同),使用注释的时候使用cacheManager ="xxxx"
使用指定的manager,当存在多个manger的时候,一定要指定一个默认的manager,使用@Primary
注解。
测试结果
已经没有乱码的情况了,缓存使用的测试代码已经写在项目里了,测试结果肯定是缓存使用成功,这里就不多贴图了。
项目地址
地址:https://github.com/a252937166/spring-boot-demo
分支:feature/redis