Guava缓存简介+demo+克隆类的使用

Guava Cache简介

Guava是谷歌提供的一个核心Java类库,其中包括新的集合类型、不可变集合、图库,以及用于并发、I/O、Hash、缓存、字符串等的 实用工具。它在谷歌中的大多数Java项目中被广泛使用,也被许多其他公司广泛使用,熟练掌握这些工具类能帮助我们快速的处理日常开发中的一些问题,比如,不可变集合、集合的转换、字符串处理、本地缓存等

日常开发中的使用场景

在我们日常的开发中,当多次获取同一份数据而数据变化不频繁时,我们可以考虑使用缓存。

这里用到的就是内存和硬盘的性能不对等,我们知道内存的读取速度很快,而硬盘相对来说比较慢

而传统的关系型数据库把数据存储在硬盘上,这样在高并发读写的场景下,就会出现性能瓶颈

这个时候,如果在数据库前面加一层缓存,把数据库里面的热点数据缓存一份到内存中,读取的时候直接从内存中取,这样就可以大大的提升读取的性能

Guava中的缓存实现

Guava中的缓存是本地缓存的实现,与ConcurrentMap相似,但不完全一样。最基本的区别就是,ConcurrentMap会一直保存添加进去的元素,除非你主动remove掉。而Guava Cache为了限制内存的使用,通常都会设置自动回收

Guava Cache的使用场景

以空间换取时间,就是你愿意用内存的消耗来换取读取性能的提升 你已经预测到某些数据会被频繁的查询 缓存中存放的数据不会超过内存空间

Guava Cache详细介绍:原文链接:https://blog.csdn.net/pzjtian/article/details/106910046

如何使用Guava Cache:

先来看一个简单示例,缓存字符串实例的大小形式。首先,我们创建ChcheLoader,用于计算存储在缓存中的值,然后我们便捷的CacheBuilder类依照规范构建缓存:

@Test
public void whenCacheMiss_thenValueIsComputed() {
    CacheLoader loader;
    loader = new CacheLoader() {
        @Override
        public String load(String key) {
            return key.toUpperCase();
        }
    };

    LoadingCache cache;
    cache = CacheBuilder.newBuilder().build(loader);

    assertEquals(0, cache.size());
    assertEquals("HELLO", cache.getUnchecked("hello"));
    assertEquals(1, cache.size());
}

因为“hello” 键对应值在缓存中没有,所以值被计算并缓存。注意,我们使用getUnchecked() 方法,如果对应值不存在,则计算并缓存值到缓存中

Guava Cache参数配置说明:

//缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时可以自动加载缓存
        LoadingCache studentCache
                //CacheBuilder的构造函数是私有的,只能通过其静态方法newBuilder()来获得CacheBuilder的实例
                = CacheBuilder.newBuilder()
                //设置并发级别为8,并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(8)
                //设置写缓存后8秒钟过期
                .expireAfterWrite(8, TimeUnit.SECONDS)
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
                .maximumSize(100)
                //设置要统计缓存的命中率
                .recordStats()
                //设置缓存的移除通知
                .removalListener(new RemovalListener() {
                    @Override
                    public void onRemoval(RemovalNotification notification) {
                        System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause());
                    }
                })
                //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
                .build(
                        new CacheLoader() {
                            @Override
                            public Student load(Integer key) throws Exception {
                                System.out.println("load student " + key);
                                Student student = new Student();
                                student.setId(key);
                                student.setName("name " + key);
                                return student;
                            }
                        }
                );

具体使用Guava缓存 java代码:

导入依赖:
                
            com.google.guava
            guava
            20.0
        
public class GuavaService {

    @Autowired
    private UserMapper userMapper;

    public LoadingCache> userListCache = CacheBuilder.newBuilder()
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .maximumSize(2)
            .build(
                    new CacheLoader>() {
                        @Override
                        public List load(String key) throws Exception {
                            return userMapper.queryUserList();
                        }
                    }
            );

    public List getUserList(){
        return userListCache.getUnchecked("ALL");
    }

}
@RestController
public class GuavaTestController {

    @Autowired
    GuavaService guavaService;

    @RequestMapping("/test1")
    public List test1(){
        return guavaService.getUserList();
    }
}

踩坑记录:在取缓存赋值给List时,直接对原List操作,导致其他地方取这个缓存的时候值发生了变化。

@RequestMapping("/test2")
    public List test2(){
        List list = guavaService.getUserList();
        User user = new User();
        user.setName("testguava");
        user.setId(5555);
        user.setMale("男");
        list.add(user);
        return list;
    }

当调用test2的时候,userListCache这个缓存值会不断增加,当缓存过期后,恢复正常。

image-20200703163215480.png

image-20200703163259110.png

正确操作应该是把缓存取出的值重新赋值给List,对新List进行操作,也就是克隆值。

@RequestMapping("/test2")
    public List test2(){
        List userList = new ArrayList();
        List list = guavaService.getUserList();
        for (User user:list) {
            userList.add(user);
        }
        User user = new User();
        user.setName("testguava");
        user.setId(5555);
        user.setMale("男");
        userList.add(user);
        return userList;
    }

这里推荐另一种方式进行该操作,使用httpclient包下的 CloneUtils.cloneObject方法进行数据的克隆。

1、导入依赖:
        
      org.apache.httpcomponents
      httpclient
      4.3.6
    
  
2、
import org.apache.http.client.utils.CloneUtils;

3、
List targets = CloneUtils.cloneObject(GuavaService.getUserList());
//然后对targets直接操作就行

你可能感兴趣的:(Guava缓存简介+demo+克隆类的使用)