孔子曰:学而不思则罔java配置,可见思考的重要性。
《从零开始学 Java – Spring 集成 Memcached 缓存配置》,整篇都是作者关于缓存的思考与选择,虽然不是干货,但其价值却胜似干货。小编认为,思考的过程非常重要,甚至比写出代码还重要,我们向大牛学习,学习其工作技巧、套路固然重要,但更高境界是学习其工作时的思考方式。
硬盘的作用毫无疑问我们大家都清楚,不就是用来存储数据文件的么?如照片、视频、各种文档或等等,肯定也有你喜欢的某位岛国老师的动作片,这个时候无论我们电脑是否关机重启它们永远在那里,不会无辜地消失掉。那内存是用来做什么的呢?我是不能准确的描述出来,所以我抄袭了下面描述内存作用的一段话:
内存就是暂时存储程序以及数据的地方,比如当我们在使用 WPS 处理文稿时,当你在键盘上敲入字符时,它就被存入内存中,当你选择存盘时,内存中的数据才会被存入硬(磁)盘。
为什么这么做?
由于硬盘 IO(读写)速度比较慢,CPU 如果运行程序的时候,所有数据都直接从硬盘中读写,会非常影响效率。所以, CPU 会将运行软件时要用的数据一次性从硬盘调用到运行速度很快的内存,然后, CPU 再与内存进行数据交换。内存是易失性存储器,只要你断了电,内存中的数据就没有了。
我们程序界有没有「内存」呢
当然有。一个简单的 Web 软件系统必须包含前端页面、后端程序、数据库、服务器等等这些最基础的东西,如果我们稍微对系统要求高一点的话,我们发现每次从数据库读取数据的时间都有些漫长,这时候的数据库可以理解为电脑中的硬盘,那我们能不能提高直接从数据库取数据的性能?或者说减少相同数据的次数。完全没问题的,因为电脑中有内存做这件事,我们程序中也有一种类似的东西叫缓存。
在程序中缓存的实现方式根据不同语言、不同框架我们可以使用的缓存系统可以不相同,但是,最后他们要做的事情都是为了提高程序的性能而生的。
如果我们来详细分一下那就太多了,我们稍微数一下大的分类,如:页面缓存、静态资源缓存、数据库缓存、开发框架缓存、内存缓存系统等等这些大的分类,在这些大类上的具体实现就太多了,我们这里只讨论利用开源的内存缓存系统构建我们项目几乎都需要的缓存服务器。
比较常用的缓存系统应该就是 Redis 和 Memcached 了吧。这里不做任何这两个技术的比较与讨论,你只需要根据你使用场景选择合适自己的就好,或者你并没有选择能力的时候,什么都别说随便用一个就行。我这里使用的 Memcached ,请不要问为什么不用 Redis 。
程序中缓存的实现方式
由于我们是基于 Spring 框架下实现缓存,我大致把缓存在 Spring 下集成的方式分为了三种:
要说哪种方式更好,我当然更偏向于注释驱动缓存方案这种方式,因为你需要在你需要缓存的方法名上打@Cacheable、@CachePut、@CacheEvict标签来实现返回数据缓存到服务器。这种方式对代码的侵入性是比较小的!这种方式有一个目前我无法解决的问题是:当你方法每次返回的数据都不一样的时候,你缓存命中率会是多少?
也有开源组件simple-spring-memcached也是这种方式,但它的实现原理其实是 AOP 方式来管理,他也是用@ReadThroughSingleCache、@InvalidateSingleCache、@UpdateSingleCache这类的标签来实现缓存,对程序来说也很友好,并且要比 Spring 的方式要更完美一些,但它依然没有解决我的上述问题。
那么我要解决的问题是:缓存命中率要高、缓存数据要尽量少,换句话说就是尽可能少的存储缓存数据并尽可能大的命中缓存。
如果解决我这种事儿逼的要求,那只能自己要实现缓存咯。这就是我们上述所说的「最原始版」方式,怎么理解这种方式,就是自己写代码定义一个缓存管理器,调用缓存客户端实现缓存管理,然后再定义你要缓存的 Model 类,接着新增一个这个类的缓存实现,就是对象的获取、增加、修改和删除,接着就是在你需要获取数据的时候通过缓存获取,修改数据的时候更新缓存java配置,删除数据的时候删除缓存。这种方式好不好?不好,首先它对代码的侵入性已经到了令人发指的地步,你想想,如果你删除数据时不小心忘记调用删除缓存了,那后果是什么呢?但是,它唯一好处可能就是比较灵活了吧,可以缓存我们想缓存的内容,来解决我们上述问题,所以,思来想去最终还是决定采用最原始的方式来实现缓存,当然,首先还是要考虑我们怎么做到缓存对代码的侵入性,以及我们怎么更方便或者说不需要改代码就实现缓存了。
总结一下
这篇文章其实是我关于缓存的思考与选择,之所以要记录下来,是觉得思考的过程非常重要,甚至比会写代码还重要。坚持看到最后的朋友,如果有什么想法,可以留言,大家一起探讨!