Spring之路(49)–Spring缓存性能提升如升天?但你真的用对了吗?

简介: 本文目录1. 背景2. 同一缓存下,只看参数不看方法名3. 缓存方法调用判断的是对象相等,而不是数值相等4. 如果参数是对象,一定要实现.equals和hashcode5. 总结

1. 背景

Spring缓存,用了确实爽,性能的提升就像俺升天了那么爽快,但是如果理解不够深,不够准确的话,会带来灾难性的问题。


比如该使用缓存的时候,实际上并没有使用缓存,这种情况,相当于缓存无效。


比如不该使用缓存的时候,缓存却跳出来了,这种情况就可怕了,意味着你拿到了不该拿的数据。


所以本文就以实际的例子,演示下Spring缓存中那些需要注意的点。


2. 同一缓存下,只看参数不看方法名

如下面的例子


@Cacheable("blogs")

public List<BlogDo> getListAsc() {

 System.out.println("升序获取blog列表");

 return null;

}


@Cacheable("blogs")

public List<BlogDo> getListDesc() {

 System.out.println("降序获取blog列表");

 return null;

}


本意是想有两个缓存,分别缓存升序的blog列表和降序的blog列表,但是由于这两个方法都是使用的名为blogs的缓存,且都没有参数,导致第二个方法会将第一个方法执行的缓存取出来:


public static void main(String[] args) throws SQLException {

 // 获取容器

 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

 // 获取blogService组件

 BlogService blogService = context.getBean("blogService", BlogService.class);

 //输出:升序获取blog列表

 blogService.getListAsc();

 //没有输出,因为直接取缓存了

 blogService.getListDesc();

}


那么这种情况该如何处理呢,有以下几种处理办法:


改为不同的缓存名称,比如一个用@Cacheable("blogsAsc"),另一个用@Cacheable("blogsDesc")。这种方法十分不推荐,因为都是面向的blog这个表,用了两个缓存,那么清除缓存的时候咋办?很麻烦!

使用参数区分,加一个枚举类型表示升序和降序,方法改为getListAsc(SortEnum.ASC)和getListAsc(SortEnum.ASC)。这种方法也不推荐,因为太麻烦了。

推荐方法是:既然都是取的博客列表,直接定义一个getList方法即可,然后对该方法添加缓存。至于排序的事情,自己取出结果后排序就是了。

3. 缓存方法调用判断的是对象相等,而不是数值相等

如下面的例子:


@Cacheable("blogs")

public Long getLong(Long a) {

 System.out.println("getLong");

 return a+1;

}

@Cacheable("blogs")

public Integer getInteger(Integer a) {

 System.out.println("getInteger");

 return a+2;

}


感觉上,如果都是对数字1进行查询,应该能触发缓存,实际上并没有,就是因为这两个对象并不相等


public class Main {

public static void main(String[] args) throws SQLException {

 // 获取容器

 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

 // 获取blogService组件

 BlogService blogService = context.getBean("blogService", BlogService.class);

 //测试

 blogService.getLong(1L);// 输出getLong

 blogService.getLong(1L);// 没有输出,因为已经有缓存

 blogService.getInteger(1);// 输出getInteger因为参数并不相等

 Integer a = 1;

 Long b = 1L;

 System.out.println(a.equals(b));// 输出false,证明这两个参数实际上不相等

}

}


4. 如果参数是对象,一定要实现.equals和hashcode

在上面我们已经说明了,缓存参数的触发,是按对象是否相等来实现的,如果没有实现.equals和hashcode,就会出现:


BlogDo blog1=new BlogDo();

   blog1.setId(1L);

   blogService.getByObject(blog1);

   blogService.getByObject(blog1);//触发缓存

   BlogDo blog2=new BlogDo();

   blog2.setId(1L);

   blogService.getByObject(blog2);//没触发缓存,因为blog1与blog2不同


注意,因为是map结构,务必要同时实现.equals和hashcode,否则判断也不准确!


5. 总结

如果感觉还不清楚的话,还可以在调试模式下去查看CacheManager的具体内容,如下:


 // 获取容器

 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

 // 获取blogService组件

 BlogService blogService = context.getBean("blogService", BlogService.class);

 //测试

 blogService.getLong(1L);// 输出getLong

 blogService.getLong(1L);// 没有输出,因为已经有缓存

 blogService.getInteger(1);// 输出getInteger因为参数并不相等

 //查看缓存

 CacheManager cacheManager=context.getBean("cacheManager", CacheManager.class);


此时我们查看缓存中的内容就好理解了,此处感兴趣的可以自己去试下,我不再详细分析了。

image.png


相关文章
|
2月前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
61 0
|
2月前
|
缓存 监控 前端开发
在资源加载优化中,如何利用浏览器缓存提升性能?
通过以上这些方法,可以有效地利用浏览器缓存来提升资源加载的性能,减少网络请求次数,提高用户体验和应用的响应速度。同时,需要根据具体的应用场景和资源特点进行灵活调整和优化,以达到最佳的效果。此外,随着技术的不断发展和变化,还需要持续关注和学习新的缓存优化方法和策略。
101 53
|
1月前
|
缓存 NoSQL Java
Spring Boot中的分布式缓存方案
Spring Boot提供了简便的方式来集成和使用分布式缓存。通过Redis和Memcached等缓存方案,可以显著提升应用的性能和扩展性。合理配置和优化缓存策略,可以有效避免常见的缓存问题,保证系统的稳定性和高效运行。
48 3
|
1月前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
63 4
|
2月前
|
缓存 监控 测试技术
如何利用浏览器的缓存来优化网站性能?
【10月更文挑战第23天】通过以上多种方法合理利用浏览器缓存,可以显著提高网站的性能,减少网络请求,加快资源加载速度,提升用户的访问体验。同时,要根据网站的具体情况和资源的特点,不断优化和调整缓存策略,以适应不断变化的业务需求和用户访问模式。
112 7
|
2月前
|
存储 缓存 Java
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
356 2
|
4月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
234 24
|
4月前
|
缓存 JavaScript 中间件
优化Express.js应用程序性能:缓存策略、请求压缩和路由匹配
在开发Express.js应用时,采用合理的缓存策略、请求压缩及优化路由匹配可大幅提升性能。本文介绍如何利用`express.static`实现缓存、`compression`中间件压缩响应数据,并通过精确匹配、模块化路由及参数化路由提高路由处理效率,从而打造高效应用。
210 17
|
3月前
|
缓存 JavaScript 前端开发
Vue 3的事件监听缓存如何优化性能?
【10月更文挑战第5天】随着前端应用复杂度的增加,性能优化变得至关重要。Vue 3 通过引入事件监听缓存等新特性提升了应用性能。本文通过具体示例介绍这一特性,解释其工作原理及如何利用它优化性能。与 Vue 2 相比,Vue 3 可在首次渲染时注册事件监听器并在后续渲染时重用,避免重复注册导致的资源浪费和潜在内存泄漏问题。通过使用 `watchEffect` 或 `watch` 监听状态变化并更新监听器,进一步提升应用性能。事件监听缓存有助于减少浏览器负担,特别在大型应用中效果显著,使应用更加流畅和响应迅速。
117 1
|
4月前
|
存储 缓存 Java
在Spring Boot中使用缓存的技术解析
通过利用Spring Boot中的缓存支持,开发者可以轻松地实现高效和可扩展的缓存策略,进而提升应用的性能和用户体验。Spring Boot的声明式缓存抽象和对多种缓存技术的支持,使得集成和使用缓存变得前所未有的简单。无论是在开发新应用还是优化现有应用,合理地使用缓存都是提高性能的有效手段。
60 1

热门文章

最新文章