Java 实现缓存的三种方式

Java 实现缓存的三种方式

文章目录

  • Java 实现缓存的三种方式
    • 一、`HashMap`实现缓存
      • `Step-1`:实现一个缓存管理类
      • `Step-2`:将缓存管理类交给 `Spring` 进行管理
      • `Step-3`:编写接口测试缓存
      • `Step-4`:结果展示
    • 二、`guava local cache` 实现
      • `Step-1`:导入`guava` 依赖
      • `Step-2`:使用`guava`创建简单缓存管理类
      • `Step-3`:使用 `guava cache`,并尝试统计命中率
    • 三、使用`redis`实现缓存
      • `Step-1`:导入`Redis` 依赖
      • `Step-2`:编写测试接口
      • `Step-3`:进行接口测试,并使用`Redis DeskTop Manager` 进行查看
    • 参考文章

一、HashMap实现缓存

​ 可以实现简单的本地缓存,但是实际开发中不推荐,我们可以简单模拟一下缓存的实现,

Step-1:实现一个缓存管理类

public class LocalCache {public static HashMap<String,String> cache = new HashMap<>();static {String name = UUID.randomUUID().toString();LocalCache.cache.put(String.valueOf(1),name);System.out.println("id为1的数据添加到了缓存");}
}
// 类中有 `static` 修饰的静态代码块,当类被加载的时候就会执行,如有不懂的可以如下博客
// https://blog.csdn.net/weixin_62636014/article/details/136851287

Tips:我们在static中完成了对缓存的初始化,你可以往缓存里面放入初始数据。

Step-2:将缓存管理类交给 Spring 进行管理

@Component
public class LocalCache {public static HashMap<String,String> cache = new HashMap<>();static {String name = UUID.randomUUID().toString();LocalCache.cache.put(String.valueOf(1),name);System.out.println("id为1的数据添加到了缓存");}@PostConstructpublic void init() {String name = UUID.randomUUID().toString();LocalCache.cache.put(String.valueOf(2),name);System.out.println("id为2的数据添加到了缓存");}
}

Tips:在将缓存管理类交给了 Spring进行管理后,在方法上加入@PostConstruct,可以使方法默认执行,注意该注解不是 Spring 框架提供,仅仅是由 Java JDK 提供的,主要是作用于 Servlet生命周期的注解,实现的是在 Bean 初始化之前自定义操作

@PostConstruct 方法在 Bean初始化中的执行顺序

  • Constructor(构造方法)

  • @Autowired(依赖注入)

  • @PostConstruct (注释的初始化方法)

Step-3:编写接口测试缓存

@RequestMapping("test")
public String test(Long id) {String name = LocalCache.cache.get(String.valueOf(id));if (name != null) {System.out.println("缓存中存在,查询缓存");System.out.println(name);return name;}System.out.println("缓存中不存在,查询数据库");// 查询数据库操作后,queryDataName方法没有写了;// 大家可以自己配一下Mybatis和JDBC进行数据库查询,达到效果是从库中查出来 name;name = queryDataName(id);System.out.println(name);LocalCache.cache.put(String.valueOf(id),name);return name;
}public String queryDataName(Long id) {String name = UUID.randomUUID().toString();return name;
}

Step-4:结果展示

​ 这个是控制台输出,每个人的随机 UUID 不一致,我这个只是一个样例

id为1的数据添加到了缓存
id为2的数据添加到了缓存
缓存中存在,查询缓存
e2eadabe-3c42-4732-b465-e085ea5faf96
缓存中不存在,查询数据库
942ffe92-454f-4046-87e5-53e8b951d2a1

二、guava local cache 实现

TipsGuavaGoogle提供的一套Java工具包,Guava Cache是一套非常完善的本地缓存机制(JVM缓存),工具类就是封装平常常用的方法,不需要你重复造轮子,节省开发人员时间,我们一般需要知道怎么使用。其设计来源于 CurrentHashMap,可以按照多种策略来清理存储在其中的缓存值且保持很高的并发读写性能。

Guava 提供以下方面的能力

  • 集合 [collections]

  • 缓存 [caching]

  • 原生类型支持 [primitives support]

  • 并发库 [concurrency libraries]

  • 通用注解 [common annotations]

  • 字符串处理 [string processing]

  • I/O 等等。

Step-1:导入guava 依赖

		<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.3-jre</version></dependency>

Step-2:使用guava创建简单缓存管理类

为了方便展示,这里面使用了5 秒的缓存保留时间。

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;@Component
public class GuavaLocalCache{private Cache<String,String> fiveSecondCache = CacheBuilder.newBuilder()//设置缓存初始大小,应该合理设置,后续会扩容.initalCapacity(10)//最大值.maximumSize(100)//并发数设置.concurrencyLevel(5)//缓存过期时间,写入后5秒钟过期.expireAfterWrite(5,TimeUnit.SECONDS)//统计缓存命中率.recordStats().build()public Cache<String,String> getFiveSecondCache() {return fiveSecondCache;} // 这里就是拿到缓存对象。public void setFiveSecondCache(Cache<String,String> fiveSecondCache) {this.fiveSecondCache = fiveSecondCache;}
}

Step-3:使用 guava cache,并尝试统计命中率

public class test {@Autowiredprivate GuavaLocalCache guavaLocalCache;@RequestMapping("guavaTest")public String guavaTest(Long id) {// 获取缓存Cache<String,String> fiveSecondCache = guavaLocalCache.getFiveSecondCache();// 从缓存中获取对象String nameCache = fiveSecondCache.getIfPresent(String.valueOf(id));// 缓存中存在if (nameCache != null) {System.out.println("缓存命中:"+ nameCache + "," + getCacheStats(fiveSecondCache));return nameCache;}// 将数据存入缓存System.out.println("缓存未命中," + getCacheStats(fiveSecondCache));nameCache = id + "-" + UUID.randomUUID().toString();fiveSecondCache.put(String.valueOf(id),nameCache);return nameCache;}public String getCacheStats(Cache<String,String> cahce) {CacheStats stats = cache.stats();return "缓冲命中率:"+stats.hitRate() +" 被清除缓冲数:" + stats.evictionCount();}}

三、使用redis实现缓存

TipsRedis (全称: Remote Dictionary Server 远程字典服务)是一个开源的使用 ANSI C语言 编写、支持网络、可基于内存亦可持久化的日志型、 Key-Value数据库 。Redis 一般被用来做缓存用的,它实际上也是一种数据库(非关系型数据库),可以对经常使用到的数据进行存储,也就是大家所说的缓存。官方给出的数据是, Redis 能达到 10w+QPS( 每秒查询速度 ) 。

Tips: 为什么 Redis 的速度比 Mysql 等这种数据快呢?

​ 因为 Redis 存储的是 key-values 格式的数据,时间复杂度是 O(1) ,即直接通过 key 查询对应的 value 。 而如 Mysql 数据库,底层的实现是 B+ 树,时间复杂度是 O(logn)

​ 最重要的一点是,数据库的数据是存储在磁盘中的,而 Redis 是存储在内存当中的,它们的速度差距不言而喻。但 Redis 也支持持久化存储

Step-1:导入Redis 依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

SpringBoot 配置文件中加入设置,我使用的是yml 形式的文件,如果没有密码的话不填就好了

  redis:# IP地址host: XXX.XXX.XXX.XXX# 密码password: XXXXXXXX# 端口,默认为6379port: 6379# 数据库索引database: 0# 连接超时时间timeout: 10slettuce:pool:# 连接池中的最小空闲连接min-idle: 1# 连接池中的最大空闲连接max-idle: 8# 连接池的最大数据库连接数max-active: 8# #连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1ms

Step-2:编写测试接口

public class TestRedis{// 下面StringRedisTemplate 是一个继承自 RedisTemplate的类@Autowiredprivate StringRedisTemplate stringRedisTemplate;@RequestMapping("/redisTest")public String redisCacheTest(Long id){String name = stringRedisTemplate.opsForValue().get(String.valueOf(id));if (name != null){System.out.println("缓存中存在,查询缓存");System.out.println(name);return name;}System.out.println("缓存中不存在,查询数据库");name = id + "-" + UUID.randomUUID().toString();System.out.println(name);stringRedisTemplate.opsForValue().set(String.valueOf(id),name);return name;}
}

Step-3:进行接口测试,并使用Redis DeskTop Manager 进行查看

参考文章

  1. 【java缓存、redis缓存、guava缓存】java中实现缓存的几种方式_java缓存cache-CSDN博客
  2. 一篇文章搞定 Redis 基础知识 - 知乎 (zhihu.com)
  3. Java本地缓存技术选型(Guava Cache、Caffeine、Encache) - 掘金 (juejin.cn)
  4. MemCache原理超详细解读(仅学习) - 知乎 (zhihu.com)
  5. PostConstruct注解详细使用说明及理解-CSDN博客
  6. PostConstruct (Java Platform SE 8 ) (oracle.com)
  7. Java开发利器Guava Cache之使用篇 - 掘金 (juejin.cn)
  8. Google guava 工具类的介绍和使用 - 掘金 (juejin.cn)
  9. Redis详细介绍(精简版)_redis 服务 精简-CSDN博客
  10. 初识Redis,看这一篇就够了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/777131.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么Python不适合写游戏?

知乎上有热门个问题&#xff1a;Python 能写游戏吗&#xff1f;有没有什么开源项目&#xff1f; Python可以开发游戏&#xff0c;但不是好的选择 Python作为脚本语言&#xff0c;一般很少用来开发游戏&#xff0c;但也有不少大型游戏有Python的身影&#xff0c;比如&#xff1…

【Linux】详解进程程序替换

一、替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支)&#xff0c;子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时&#xff0c;该进程的用户空间代码和数据完全被新程序替换&#xff0c;从新程序的启动例程开始执…

Mysql数据库——高级SQL语句补充

目录 一、子查询——Subquery 1.环境准备 2.In——查询已知的值的数据记录 2.1子查询——Insert 2.2子查询——Update 2.3子查询——Delete 3.Not In——表示否定&#xff0c;不在子查询的结果集里 3.Exists——判断查询结果集是否为空 4.子查询——别名 二、视图—…

Channel 阻塞机制、死锁问题

Channel 阻塞机制 在Go语言中&#xff0c;channel是用于在不同的goroutine之间进行通信的主要机制。channel的阻塞机制确保了数据的同步传输&#xff0c;这意味着在某些情况下&#xff0c;操作channel的goroutine可能会被挂起&#xff08;阻塞&#xff09;&#xff0c;直到另一…

C 传递数组给函数

如果您想要在函数中传递一个一维数组作为参数&#xff0c;您必须以下面三种方式来声明函数形式参数&#xff0c;这三种声明方式的结果是一样的&#xff0c;因为每种方式都会告诉编译器将要接收一个整型指针。同样地&#xff0c;您也可以传递一个多维数组作为形式参数。 方式 1…

PointNet++点云处理原理

PointNet点云处理原理 借鉴了多层神经网络的思想 pointnet要么是一个点&#xff0c;要么是所有点进行操作&#xff0c;就不会有局部上下文信息 pointnet基本思想是迭代地应用到局部区域 1.多级别特征学习 2.旋转不变性 3.置换不变性 选取中心点centroid&#xff0c;通过poi…

《c++》纯虚函数和抽象类

在C中&#xff0c;纯虚函数和抽象类是面向对象编程中的重要概念&#xff0c;用于实现多态性和接口定义 1.纯虚函数&#xff08;Pure Virtual Function&#xff09;&#xff1a; 纯虚函数是在基类中声明的虚函数&#xff0c;但没有提供实现。它们以关键字声明&#xff0c;并在函…

jconsole jvisualvm

jconsole 打开方式 命令行输入 jconsole双击想要连接的应用 界面展示 jvisualvm 打开方式 命令行输入 jvisualvm双击想要连接的应用 可以安装插件&#xff0c;比如 Visual GC 直观看到 GC 过程

在CentOS7上部署Nginx并测试指南

Nginx部署测试 Nginx简介 Nginx是俄罗斯人Igor Sysoev编写的一款高性能的HTTP和反向代理服务器。 Nginx选择了epoll和kqueue作为网络I/O模型&#xff0c;在高连接并发的情况下&#xff0c;内存、CPU等系统资源消耗非常低&#xff0c;运行稳定。 正向代理与反向代理 正向代…

Java学习记录第十三天

面向对象编程 核心思想就是OOP&#xff08;面向对象编程&#xff09; 面向过程&面向对象 面向过程思想 步骤清晰简单&#xff0c;第一步做什么&#xff0c;第二步做什么... 面对过程适合处理一些较为简单的问题 面向对象思想 物以类聚&#xff0c;分类的思维模式&…

Redis慢日志!!!

用途&#xff1a;系统优化&#xff0c;将执行较慢的sql记录下来&#xff0c;然后对其进行优化。 1.慢查询日志的两个配置项 slowlog-log-slower-than Redis 慢查询日志的时间阈值&#xff0c;单位微妙。 1) 值为正数&#xff0c;执行时间大于该值设置的微秒时才记录到慢日志中…

电源噪声的起因及危害

对造成电源不稳定的根源进行简单分析如下,主要在于两个方面:一是器件高速开关状态下,瞬态的交变电流过大;二是电流回路上存在的电感。从表现形式上来看又可以分为三类:同步开关噪声(SSN),有时被称为Δi噪声,地弹(Ground bounce)现象也可归于此类(图1-a);非理想电…

2024.3.21 QT

QT登录界面设计&#xff1a; //头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMovie>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nu…

Qt——Qt文本读写之QFile与QTextStream的使用总结(打开文本文件,修改内容后保存至该文件中)

【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C++语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实战》

【AI】安装web UI时总是报找不到yaml

【背景】 text generation web ui是为本地hosting提供AI服务而出现的前端框架&#xff0c;后端可以自由下载hugging face上的model&#xff0c;load后就可以直接在Web UI上访问。这个服务可以自由架构在局域网上供内网用户访问。 我觉得挺满足自己需要&#xff0c;就在windows…

Linux manim安装

简介 根据文档可知, manim目前分为两个版本, 一个是由3Blue1Brown维护更新的最新版本的manimgl, 另一个是稳定的社区版本manim or manimce. 两个版本在安装和使用上都有些不同, 不要搞混. Linux manim ERROR No package ‘pangocairo’ found Getting requirements to buil…

C++进阶之路---C++11新特性 | lambda表达式

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 前言&#xff1a;简介lambda 在C中&#xff0c;lambda表达式是一种匿名函数的方式&#xff0c;它可以用来解决以下问题&a…

稀碎从零算法笔记Day26-LeetCode:跳跃游戏

断更多天&#xff0c;懒狗ex 题型&#xff1a;数组、模拟、类似双指针&#xff1f; 链接&#xff1a;55. 跳跃游戏 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组…

【Diffusers库】第四篇 训练一个扩散模型(Unconditional)

目录 写在前面的话下载数据模型配置文件加载数据创建一个UNet2DModel创建一个调度器训练模型完整版代码&#xff1a; 写在前面的话 这是我们研发的用于 消费决策的AI助理 &#xff0c;我们会持续优化&#xff0c;欢迎体验与反馈。微信扫描二维码&#xff0c;添加即可。   官方…

uni-app中web-view的使用

1. uni-app中web-view的使用 uni-app中的web-view是一个 web 浏览器组件&#xff0c;可以用来承载网页的容器&#xff0c;uni-app开发的app与web-view实现交互的方式相关简单&#xff0c;应用通过属性message绑定触发事件&#xff0c;然后在web-view的网页向应用 postMessage 触…