Spring Boot中的缓存支持(一)注解配置与EhCache使用

随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一。Spring 3开始提供了强大的基于注解的缓存支持,可以通过注解配置方式低侵入的给原有Spring应用增加缓存功能,提高数据访问性能。

在Spring Boot中对于缓存的支持,提供了一系列的自动化配置,使我们可以非常方便的使用缓存。下面我们通过一个简单的例子来展示,我们是如何给一个既有应用增加缓存功能的。

快速入门

首先,下载样例工程chapter3-2-2。本例通过spring-data-jpa实现了对User用户表的一些操作,若没有这个基础,可以先阅读《使用Spring-data-jpa简化数据访问层》一文对数据访问有所基础。

准备工作

为了更好的理解缓存,我们先对该工程做一些简单的改造。

  • application.properties文件中新增spring.jpa.properties.hibernate.show_sql=true,开启hibernate对sql语句的打印

  • 修改单元测试ApplicationTests,初始化插入User表一条用户名为AAA,年龄为10的数据。并通过findByName函数完成两次查询。


@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTests {

@Autowired
private UserRepository userRepository;

@Before
public void before() {
userRepository.save(new User("AAA", 10));
}

@Test
public void test() throws Exception {
User u1 = userRepository.findByName("AAA");
System.out.println("第一次查询:" + u1.getAge());

User u2 = userRepository.findByName("AAA");
System.out.println("第二次查询:" + u2.getAge());
}

}
  • 执行单元测试,我们可以在控制台中看到下面内容。
Hibernate: insert into user (age, name) values (?, ?)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第一次查询:10
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第二次查询:10

在测试用例执行前,插入了一条User记录。然后每次findByName调用时,都执行了一句select语句来查询用户名为AAA的记录。

引入缓存

  • pom.xml中引入cache依赖,添加如下内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
  • 在Spring Boot主类中增加@EnableCaching注解开启缓存功能,如下:
@SpringBootApplication
@EnableCaching
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}
  • 在数据访问接口中,增加缓存配置注解,如:
@CacheConfig(cacheNames = "users")
public interface UserRepository extends JpaRepository<User, Long> {

@Cacheable
User findByName(String name);

}
  • 再来执行以下单元测试,可以在控制台中输出了下面的内容:
Hibernate: insert into user (age, name) values (?, ?)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第一次查询:10
第二次查询:10

到这里,我们可以看到,在调用第二次findByName函数时,没有再执行select语句,也就直接减少了一次数据库的读取操作。

为了可以更好的观察,缓存的存储,我们可以在单元测试中注入cacheManager。

@Autowired
private CacheManager cacheManager;

使用debug模式运行单元测试,观察cacheManager中的缓存集users以及其中的User对象的缓存加深理解。

Cache注解详解

回过头来我们再来看,这里使用到的两个注解分别作了什么事情。

  • @CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置。在这里@CacheConfig(cacheNames = "users"):配置了该数据访问对象中返回的内容将存储于名为users的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义。

  • @Cacheable:配置了findByName函数的返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问。该注解主要有下面几个参数:

    • valuecacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了
    • key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = "#p0"):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档
    • condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有当第一个参数的长度小于3的时候才会被缓存,若做此配置上面的AAA用户就不会被缓存,读者可自行实验尝试。
    • unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
    • keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的
    • cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
    • cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。

除了这里用到的两个注解之外,还有下面几个核心注解:

  • @CachePut:配置于函数上,能够根据参数定义条件来进行缓存,它与@Cacheable不同的是,它每次都会真是调用函数,所以主要用于数据新增和修改操作上。它的参数与@Cacheable类似,具体功能可参考上面对@Cacheable参数的解析
  • @CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除相应数据。除了同@Cacheable一样的参数之外,它还有下面两个参数:
    • allEntries:非必需,默认为false。当为true时,会移除所有数据
    • beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。

缓存配置

完成了上面的缓存实验之后,可能大家会问,那我们在Spring Boot中到底使用了什么缓存呢?

在Spring Boot中通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),Spring Boot根据下面的顺序去侦测缓存提供者:

  • Generic
  • JCache (JSR-107)
  • EhCache 2.x
  • Hazelcast
  • Infinispan
  • Redis
  • Guava
  • Simple

除了按顺序侦测外,我们也可以通过配置属性spring.cache.type来强制指定。我们可以通过debug调试查看cacheManager对象的实例来判断当前使用了什么缓存。

本文中不对所有的缓存做详细介绍,下面以常用的EhCache为例,看看如何配置来使用EhCache进行缓存管理。

在Spring Boot中开启EhCache非常简单,只需要在工程中加入ehcache.xml配置文件并在pom.xml中增加ehcache依赖,框架只要发现该文件,就会创建EhCache的缓存管理器。

  • src/main/resources目录下创建:ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">

<cache name="users"
maxEntriesLocalHeap="200"
timeToLiveSeconds="600">
</cache>

</ehcache>
  • pom.xml中加入
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>

完成上面的配置之后,再通过debug模式运行单元测试,观察此时CacheManager已经是EhCacheManager实例,说明EhCache开启成功了。

对于EhCache的配置文件也可以通过application.properties文件中使用spring.cache.ehcache.config属性来指定,比如:

spring.cache.ehcache.config=classpath:config/another-config.xml

代码示例

本文的相关例子可以查看下面仓库中的chapter4-4-1目录:

  • Github:https://github.com/dyc87112/SpringBoot-Learning
  • Gitee:https://gitee.com/didispace/SpringBoot-Learning

【转载请注明出处】:http://blog.didispace.com/springbootcache1/


money.jpg

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

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

相关文章

LeetCode 1361. 验证二叉树(图的出入度)

1. 题目 二叉树上有 n 个节点&#xff0c;按从 0 到 n-1 编号&#xff0c;其中节点 i 的两个子节点分别是 leftChild[i] 和 rightChild[i]。 只有 所有 节点能够形成且 只 形成 一颗 有效的二叉树时&#xff0c;返回 true&#xff1b;否则返回 false。 如果节点 i 没有左子节…

微软:我已把显存优化做到了极致,还有谁?

文 | 王思若大家好&#xff0c;我是王思若。17年6月Google提出了Transformer架构&#xff0c;这篇目前Citation 4.3万的文章开启了大规模预训练模型时代。或者&#xff0c;更精确的从18年OpenAI和Google分别基于其中的Decoder和Encoder发布的大规模预训练模型GPT1和BERT开始&am…

Spring Boot中使用JavaMailSender发送邮件

相信使用过Spring的众多开发者都知道Spring提供了非常好用的JavaMailSender接口实现邮件发送。在Spring Boot的Starter模块中也为此提供了自动化配置。下面通过实例看看如何在Spring Boot中使用JavaMailSender发送邮件。 快速入门 在Spring Boot的工程中的pom.xml中引入sprin…

LeetCode 1362. 最接近的因数

1. 题目 给你一个整数 num&#xff0c;请你找出同时满足下面全部要求的两个整数&#xff1a; 两数乘积等于 num 1 或 num 2以绝对差进行度量&#xff0c;两数大小最接近 你可以按任意顺序返回这两个整数。 示例 1&#xff1a; 输入&#xff1a;num 8 输出&#xff1a;[3…

光子神经网络登上nature,图像识别速度降至1纳秒

文 | Alex&#xff08;凹非寺&#xff09;源 | 量子位比深度神经网络速度还快的是什么&#xff1f;或许光子DNN可以回答这个问题。现在&#xff0c;美国研究者开发的一个光子神经网络(photonic deep neural network&#xff0c;PDNN)&#xff0c;让图像识别仅需1纳秒。1纳秒是什…

LeetCode 1363. 形成三的最大倍数(贪心,难)

1. 题目 给你一个整数数组 digits&#xff0c;你可以通过按任意顺序连接其中某些数字来形成 3 的倍数&#xff0c;请你返回所能得到的最大的 3 的倍数。 由于答案可能不在整数数据类型范围内&#xff0c;请以字符串形式返回答案。 如果无法得到答案&#xff0c;请返回一个空…

Spring Boot中使用Spring Security进行安全控制

我们在编写Web应用时&#xff0c;经常需要对页面做一些安全控制&#xff0c;比如&#xff1a;对于没有访问权限的用户需要转到登录表单页面。要实现访问控制的方法多种多样&#xff0c;可以通过Aop、拦截器实现&#xff0c;也可以通过框架实现&#xff08;如&#xff1a;Apache…

这篇寒门博士论文致谢火了:回首望过去,可怜无数山

源 | 奔流新闻兰州晨报 记者 邢剑扬、安之若素德之至 微信平台、澎湃新闻“可怜无数山”近日&#xff0c;一位甘肃籍博士的论文致谢和回望“火”了&#xff0c;有网友称读后“泪眼婆娑&#xff0c;戳到了灵魂”&#xff0c;也有网友评价“一字一句&#xff0c;熠熠生辉”。“回…

Spring Boot中的事务管理

什么是事务&#xff1f; 我们在开发企业应用时&#xff0c;对于业务人员的一个操作实际是对数据读写的多步操作的结合。由于数据操作在顺序执行的过程中&#xff0c;任何一步操作都有可能发生异常&#xff0c;异常会导致后续操作无法完成&#xff0c;此时由于业务逻辑并未正确…

C++类对象排序operator重载操作

类内默认含有this指针&#xff0c;bool operator(const T& a)类外则需要写两个参数&#xff0c;bool operator(const T& a, const T& b) class People { public:string name;int id;People(string n, int i):name(n),id(i){}bool operator(const People& a){r…

鹅厂计算机视觉,世界第二??

编 | 好困 桃子源 | 新智元腾讯的计算机视觉能力首次进入全球Top2的评分排名&#xff01;Gartner最新发布的2022年度《Magic Quadrant for Cloud AI Developer Services》是业内权威的云计算评估报告之一&#xff0c;评估对象包括亚马逊、微软、谷歌等全球云厂商。在核心产品能…

Spring Boot中使用log4j实现http请求日志入mongodb

之前在《使用AOP统一处理Web请求日志》一文中介绍了如何使用AOP统一记录web请求日志。基本思路是通过aop去切web层的controller实现&#xff0c;获取每个http的内容并通过log4j将日志内容写到应用服务器的文件系统中。 但是当我们在集群中部署应用之后&#xff0c;应用请求的日…

程序员面试金典 - 面试题 01.02. 判定是否互为字符重排(哈希map)

1. 题目 给定两个字符串 s1 和 s2&#xff0c;请编写一个程序&#xff0c;确定其中一个字符串的字符重新排列后&#xff0c;能否变成另一个字符串。 示例 1&#xff1a; 输入: s1 "abc", s2 "bca" 输出: true 示例 2&#xff1a; 输入: s1 "abc&…

破局数据困境,迭代一年的终版解决方案竟是纯规则方法!

文 | Severus大家好&#xff0c;我是Severus&#xff0c;一个致力于做好中文自然语言理解的老程序员。一年前&#xff0c;我在萌屋的第一篇推文&#xff08;在错误的数据上&#xff0c;刷到 SOTA 又有什么意义&#xff1f;&#xff09;中&#xff0c;重点讲述了关系抽取任务所面…

程序员面试金典 - 面试题 01.03. URL化(字符串)

1. 题目 URL化。编写一种方法&#xff0c;将字符串中的空格全部替换为%20。假定该字符串尾部有足够的空间存放新增字符&#xff0c;并且知道字符串的“真实”长度。&#xff08;注&#xff1a;用Java实现的话&#xff0c;请使用字符数组实现&#xff0c;以便直接在数组上操作。…

扩散模型又杀疯了!这一次被攻占的领域是...

文 | Yimin_饭煲从2020年的初出茅庐&#xff0c;到2021年的日趋火热&#xff0c;再到2022年的大放异彩&#xff0c;扩散模型(Diffusion Models) 正在人工智能学术界和工业界获取越来越多的关注。如果还不是特别了解扩散模型的朋友&#xff0c;可以阅读卖萌屋的几篇历史推文《扩…

程序员面试金典 - 面试题 01.04. 回文排列(哈希map)

1. 题目 给定一个字符串&#xff0c;编写一个函数判定其是否为某个回文串的排列之一。 回文串是指正反两个方向都一样的单词或短语。排列是指字母的重新排列。 回文串不一定是字典当中的单词。 示例1&#xff1a; 输入&#xff1a;"tactcoa" 输出&#xff1a;tru…

Spring Boot中对log4j进行多环境不同日志级别的控制

之前介绍了在《Spring boot中使用log4j记录日志》&#xff0c;仅通过log4j.properties对日志级别进行控制&#xff0c;对于需要多环境部署的环境不是很方便&#xff0c;可能我们在开发环境大部分模块需要采用DEBUG级别&#xff0c;在测试环境可能需要小部分采用DEBUG级别&#…

耗时四年,我们写了一本1400页的AI全栈技术手册

不知不觉写文章已经四年了。最开始是一个人&#xff0c;后来恰了恰饭&#xff0c;就招揽了很多比小夕厉害的小伙伴一起写。不知不觉已经积累了300多篇了。。三年以来&#xff0c;我跟小伙伴们原创的300篇深度学习、NLP、CV、知识图谱、跨模态等领域的入门资料、子方向综述、201…

程序员面试金典 - 面试题 01.06. 字符串压缩(字符串)

1. 题目 字符串压缩。利用字符重复出现的次数&#xff0c;编写一种方法&#xff0c;实现基本的字符串压缩功能。比如&#xff0c;字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短&#xff0c;则返回原先的字符串。你可以假设字符串中只包含大小写英文字母&…