前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用本地缓存

使用本地缓存

作者头像
叔牙
发布2020-11-19 14:45:46
1.8K0
发布2020-11-19 14:45:46
举报
文章被收录于专栏:一个执拗的后端搬砖工

缓存是高并发程序开发中的一大利器,利用缓存我们能够显著有效的提高程序的响应能力,缓存服务器和数据库的压力,市面上常用的缓存有单机缓存memcached,集群缓存redis等等,

对于大型互联网项目的高并发场景我们使用第三方缓存插件是首选,但是对于一些并发不是很大,但是频繁访问数据库也会影响性能和带来压力的一些场景,我们可以是用本地缓存来

提高程序响应速度和缓解服务器和数据可压力,常用的本地缓存有guava的本地cache,以及各个公司自己封装的本地缓存插件(本质上本地缓存是使用Map实现的,差别在于实现方式和性能)

,此篇就使用guava实现本地缓存展开叙述:

一、新建maven项目&添加依赖

新建一个通用的maven工程,并添加一下guava依赖:

<dependency>

<groupId>com.google.guava</groupId>

<artifactId>guava</artifactId>

<version>18.0</version>

</dependency>

二、实现本地缓存

我们借助guava的本地缓存并对其封装,实现我们的本地缓存操作工具类,实现方式如下:

package com.typhoon.demo1.cache;

import java.util.List;

import java.util.concurrent.Callable;

import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.builder.ToStringBuilder;

import com.google.common.cache.Cache;

import com.google.common.cache.CacheBuilder;

/**

* guava本地缓存工具类

*

* @author Typhoon

* @date 2017-05-24 15:48

* @since V2.0

*/

public abstract class LocalCacheUtil {

// private static final Logger LOGGER =

// LoggerFactory.getLogger(LocalCacheUtil.class);

private static Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(100)

.expireAfterWrite(24, TimeUnit.HOURS).recordStats().build();

/**

* 放入本地缓存

*

* @author Typhoon

* @date 2017-05-24 16:34

* @since V2.0

* @param key

* @param value

*/

public static void put(Object key, Object value) {

if (null == key) {

throw new IllegalArgumentException("key can not be null");

}

cache.put(key, value);

}

/**

* 根据key获取value

*

* @author Typhoon

* @date 2017-05-24 15:51

* @since V2.0

* @description

* <ul>

* <li>如果key存在返回对应value</li>

* <li>如果key不存在返回null</li>

* <li>注*:cache.get(key,Callable

* <Object>)不允许key不存在的情况,但是实际情况下是允许的,需要外层捕获异常</li>

* </ul>

* @param key

* @return <code>Object</code>

*/

public static Object get(Object key) {

if (null == key) {

throw new IllegalArgumentException("key can not be null");

}

return cache.getIfPresent(key);

}

/**

* <ul>

* <li>根据key获取value,如果获取为null,根据传入的callable使用其他方式获取</li>

* <li>如果穿进来callable为null,调用<method>get(key)</method></li>

* </ul>

*

* @author Typhoon

* @date 2017-05-24 16:07

* @since V2.0

* @param key

* @param callable

* @return <result>Object</result>

*/

public static Object get(Object key, Callable<? extends Object> callable) {

if (null == key) {

throw new IllegalArgumentException("key can not be null");

}

if (null == callable) {

return get(key);

}

Object value = null;

try {

value = cache.get(key, callable);

} catch (Exception e) {

e.printStackTrace();

}

return value;

}

/**

* 失效某个key

*

* @author Typhoon

* @date 2017-05-24 16:09

* @since V2.0

* @param key

*/

public static void invalidateKey(Object key) {

if (null == key) {

throw new IllegalArgumentException("key can not be null");

}

cache.invalidate(key);

}

/**

* 失效某个key集

*

* @author Typhoon

* @date 2017-05-24 16:09

* @since V2.0

* @param keys

*/

public static void invalidateKeys(List<Object> keys) {

if (null == keys || keys.size() == 0) {

throw new IllegalArgumentException("keys can not be empty");

}

cache.invalidateAll(keys);

}

}

分析:

  • 上述截图中代码片段创建了一个缓存管理器,设置了最大缓存个数是100,有效时间是24小时
  • 上述这段代码实现将数据放入缓存
  • 这段代码实现从本地缓存中取目标数据,guava缓存中的get方法是不允许key不存在的,不存在时候会抛异常出来,但是我们的实际业务场景中是允许key不存在的,所以我们使用getIfpresent方法,允许key不存在
  • 这段代码是对get方法的重载,可以传进来一个callable,也就是我们首先根据key去本地缓存中取查看数据,如果没有查到就根据传进来的callable逻辑去查询并返回结果,常见的就是callable中使用DB查询

注意:如果callable没有传就是用上一个方法get

  • 这段代码有两个方法,都是失效本地缓存中的key,一个是单个失效一个是批量失效

三、测试本地缓存

编写单元测试类并测试本地缓存:

package com.typhoon.demo1.consumer;

import java.util.concurrent.Callable;

import org.apache.commons.lang3.builder.ToStringBuilder;

import com.typhoon.demo1.cache.LocalCacheUtil;

import com.typhoon.demo1.dao.UserDao;

import com.typhoon.demo1.entity.User;

public class LocalCacheConsumer {

public static void main(String[] args) {

final Long id = 1L;

String key = "user:id" + id;

Object obj = LocalCacheUtil.get(key, new Callable<User>() {

public User call() throws Exception {

// TODO Auto-generated method stub

return new UserDao().getUserById(id);

}

});

System.out.println(ToStringBuilder.reflectionToString(obj));

}

}

我们只测试一个方法,上述代码中可以发现,调用得失get(key,callable)方法,

如果本地缓存中根据key查不到数据,会使用callable中的new UserDao().getUserById(id)去数据库查询并返回结果,

运行单元测试方法,可以看到如下结果:

可以看到,我们已经拿到想要的结果.

总结

在有些场景下我们使用本地缓存更加方便和轻量级,但是任何一种事物都有其双面性,我们可以分析出本地缓存的优缺点:

  • 优点:1)使用方便 2)更轻量级
  • 缺点:1)不适合大中型项目中的高并发场景,如果强行使用,会拖垮整个应用(本地缓存占用jvm内存) 2)不适合复杂的缓存场景 3)仍然存在缓存穿透问题

ps:原创不易,多多支持!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-08-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PersistentCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档