一、前言:
港真,一直也在用redis,知道它能加速存取数据,但是还真没有自己对比过差距。也都是一直配置redis,然后直接上代码。今天就来做一个实际的例子,毕竟实践才是检验真理的唯一标准吗。
二、准备:
2.1 数据
一张有200W数据的表。
不错,我们要做的就是一次查这200W数据,对比使用redis缓存和不用redis缓存的时间差。
上面两张图就是我准备的数据了。这些还是之前看表分区查询效果的时候在网上找的例子。用一个存储过程往表里差了200W条数据。
2.2 springboot+springcloud项目
有了数据那就该有用武之地了。我搭建得是springboot+springcloud得架构。不过这篇文章只是为了整合redis,以及肉眼观察效果,就不详细介绍srpingboot+springcloud得项目搭建步骤了。以后有时间再写笔记吧。
上图就是我得架构了。今天用到得也就一个注册中心,一个api,一个impl。不过最终都要到zuul网关调用,通过controller层进行消费。网关和服务消费这些都不是这个笔记得重点,就不在这里写了。以后在项目搭建得笔记里会详细记得。
三、开干:
该用的东西都准备好了。那就开始上代码吧:
3.1 api层
首先就是api了,里面很简单,就一个实体类,一个service接口。忽略我得结构,因为用的是双数据源,才在service下面又分了一层master和test。
Tab实体类:
@Data
public class Tab implements Serializable {
private String c1;
private String c2;
private String c3;
}
@FeignClient(value = "master-impl")
public interface Test2Service {
@RequestMapping(value="/test2/findAll",method = RequestMethod.GET)
public List<Tab> getAll();
3.2 impl层
上图是我得Impl层。这是整合了redis后得最终结构。
下面先说一下没有使用redis时得效果:
Test2Mapper.java代码:
@Repository("test2Mapper")
@Mapper
public interface Test2Mapper {
public List<Tab> getAll();
}
TestServiceImpl 代码
@Service("test2Service")
public class TestServiceImpl implements Test2Service {
@Resource(name="test2Mapper")
Test2Mapper test2Mapper;
@Override
public List<Tab> getAll() {
return test2Mapper.getAll();
}
}
TestController代码:
@Controller
public class TestController {
Logger logger = LoggerFactory.getLogger(TestController.class);
@Autowired
private Test2Service test2Service;
@RequestMapping("/test/findAll")
@ResponseBody
public List<Tab> testFindAll() {
logger.info("进入provider的testFindAll的controller方法!");
long currentTimeMillis = System.currentTimeMillis();
logger.info("现在时间:"+currentTimeMillis);
List<Tab> list = test2Service.getAll();
long nowMills = System.currentTimeMillis();
logger.info("查询到数据有:"+list.size());
logger.info("结束时间:"+nowMills);
logger.info("查询花费时间为:"+(nowMills-currentTimeMillis)/1000);
return list;
}
}
启动项目,访问之后,在没有配置redis缓存得情况下,第一次查询时间时38秒(尼玛,我之前每次测都是50+甚至60+,这次怎么这么优秀,都学会自己优化了?)
第二次访问,时间为39秒。
下面加入redis缓存,看一下效果。
pom文件添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</exclusion>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加jedis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
application.yml文件配置redis
spring:
redis: # REDIS (RedisProperties)
database: 0 # Redis数据库索引(默认为0)
host: localhost # Redis服务器地址
port: 6379 # Redis服务器连接端口
password: # Redis服务器连接密码(默认为空)
timeout: 1000 # 连接超时时间(毫秒)
jedis:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
新增CacheConfig 类
@Configuration
// 必须加,使配置生效
@EnableCaching
public class CacheConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.database}")
private int database;
/**
* 键的生成策略
* @return
* 规则:目标类名称+方法名+参数名
*/
@Bean
public KeyGenerator wiselyKeyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... 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
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(host);
factory.setPort(port);
factory.setTimeout(timeout);
factory.setDatabase(database);
return factory;
}
/**
* 配置CacheManager 管理cache
* @param
* @return
*/
// @Bean
// public CacheManager cacheManager(RedisTemplate redisTemplate) {
// RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// cacheManager.setDefaultExpiration(60*60); // 设置key-value超时时间
// return cacheManager;
// }
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
修改Mapper文件
@Repository("test2Mapper")
@Mapper
@CacheConfig(cacheNames = "Test2Mapper") //新增部分
public interface Test2Mapper {
@Cacheable //新增部分
public List<Tab> getAll();
}
重启服务,再次访问:
首次访问用了63秒(这应该才是正常水平,以前每次访问都是60左右。)
通过redis可视化工具可以看到Test2Mapper已经在redis缓存里了。
再次访问:
可以看到用了redis缓存后,再次访问时间只有8秒。远比60秒或者30+秒用时少。
欧了,redis缓存效果通过这个小DEMO已经很直观了。有哪些不正确得地方还请大神指正。多谢了!