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

SpringBoot中的Cache缓存

1、基本概念

Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;同时支持JCache(JSR-107)注解。

Cache 缓存接口,定义缓存操作,实现有:RedisCache、EhCacheCache、ConcurrentMapCache等
CacheManager 缓存管理器,管理各种缓存(Cache)组件
@Cacheable 针对方法配置,根据方法的请求参数对其结果进行缓存
@CacheEvict 清空缓存
@CachePut 保证方法被调用,又希望结果被缓存 update,调用,将信息更新缓存
@EnableCaching 开启基于注解的缓存
KeyGenerator 缓存数据时key生成的策略
serialize 缓存数据时value序列化策略

2、整合项目

1、新建一个SpringBoot1.5+web+mysql+mybatis+cache

2、编写配置文件,连接Mysql

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.1.125:3306/test01
spring.datasource.username=root
spring.datasource.password=root
mybatis.configuration.map-underscore-to-camel-case=true
server.port=9000

3、创建JaveBean实例

public class Employee {
private Integer id;
private String lastName;
private String gender;
private String email;
private Integer dId; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getLastName() {
return lastName;
} public void setLastName(String lastName) {
this.lastName = lastName;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public String getEmail() {
return email;
} public void setEmail(String email) {
this.email = email;
} public Integer getdId() {
return dId;
} public void setdId(Integer dId) {
this.dId = dId;
} @Override
public String toString() {
return "Employee{" +
"id=" + id +
", lastName='" + lastName + '\'' +
", gender='" + gender + '\'' +
", email='" + email + '\'' +
", dId=" + dId +
'}';
}
}

4、创建mapper接口映射数据库,并访问数据库中的数据

import com.wdjr.cache.bean.Employee;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update; @Mapper
public interface EmployeeMapper { @Select("SELECT * FROM employee WHERE id = #{id}")
public Employee getEmpById(Integer id);
@Update("UPDATE employee SET lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId} WHERE id=#{id}")
public void updateEmp(Employee employee);
}

5、在pom.xml中引入cache依赖

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

6、主程序添加注解MapperScan,并且使用@EnableCaching,开启缓存功能

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching; @EnableCaching
@MapperScan("com.wdjr.cache.mapper")
@SpringBootApplication
public class Springboot01CacheApplication { public static void main(String[] args) {
SpringApplication.run(Springboot01CacheApplication.class, args);
}
}

7、编写service,来具体实现mapper中的方法,使用@Cacheable增加缓存

import com.wdjr.cache.bean.Employee;
import com.wdjr.cache.mapper.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; @Service
public class EmployeeService { @Autowired
EmployeeMapper employeeMapper; /**
* 将方法的运行结果进行缓存,以后要是再有相同的数据,直接从缓存中获取,不用调用方法
* CacheManager中管理多个Cache组件,对缓存的真正CRUD操作在Cache组件中,每个缓存组件都有自己的唯一名字;
*
* 属性:
* CacheName/value:指定存储缓存组件的名字
* key:缓存数据使用的key,可以使用它来指定。默认是使用方法参数的值,或方法的返回值
* 编写Spel表达式:#id 参数id的值, #a0/#p0 #root.args[0]
* keyGenerator:key的生成器,自己可以指定key的生成器的组件id
* key/keyGendertor二选一使用
*
* cacheManager指定Cache管理器,或者cacheReslover指定获取解析器
* condition:指定符合条件的情况下,才缓存;
* unless:否定缓存,unless指定的条件为true,方法的返回值就不会被缓存,可以获取到结果进行判断
* sync:是否使用异步模式,unless不支持
*
*
*/
@Cacheable(cacheNames = {"emp"},key = "#id",condition = "#id>0",unless = "#result==null")
public Employee getEmp(Integer id){
System.out.println("查询id= "+id+"的员工");
return employeeMapper.getEmpById(id);
}
}

8、编写controller测试

@RestController
public class EmployeeController {
@Autowired
EmployeeService employeeService; @GetMapping("/emp/{id}")
public Employee getEmp(@PathVariable("id")Integer id){
return employeeService.getEmp(id);
}
}

9、查看结果。具体结果就不截图了,缓存功能开启, 如果条件相同,只会查询一次数据库。

Cache注解

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

    •   该注解是整合了Cacheable /Cacheput / CacheEvict。设置在类上,该类的方法上面的cache注解均不用设置name。
  • @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:既调用方法,又更新缓存数据。也就是修改数据库的某个数据,同时更新缓存。步骤:先运行方法,再将目标结果缓存起来。

    • 如果需要使用该注解,不仅需要加入注解,还需要设置注解的key的值需要和查询出来的key一致,否则不会改变cache缓存中的数据。
  • @CacheEvict:清除缓存。使用key删除缓存数据。
    • 特有的两个属性:

      • allEntries = true,代表不论清除哪个key,都重新刷新缓存
      • beforeInvocation=true.方法执行前,清空缓存,无论发不发生异常,都会清除缓存。false则是方法执行后,情况缓存。默认是false,如果程序异常,就不会清除缓存。

使用Redis做集中式缓存

默认的缓存是在内存中定义HashMap,在实际的开发生产中,经常使用Redis作为缓存中间件,而不使用cache。

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。也是以key-value的形式进行存储数据的一款非关系型数据库。

步骤:

1、安装Redis:将安装redis在虚拟机中(docker)。  推荐去docker中国中去下载。

#拉取redis镜像
docker pull redis
#启动redis,并对外发开,使外部可以连接到虚拟机中的rdeis
docker run -d -p 6379:6379 --name redis01 bfcb1f6df2db

安装后可以使用 Redis Desktop Manager管理工具去管理redis。

2、Redis的Tempate

Redis的常用五大数据类型

String【字符串】、List【列表】、Set【集合】、Hash【散列】、ZSet【有序集合】

分为两种一种是StringRedisTemplate,另一种是RedisTemplate

根据不同的数据类型,大致的操作也分为这5种,以StringRedisTemplate为例

tringRedisTemplate.opsForValue()  --String
stringRedisTemplate.opsForList() --List
stringRedisTemplate.opsForSet() --Set
stringRedisTemplate.opsForHash() --Hash
stringRedisTemplate.opsForZset() -Zset

 a.导入Redis依赖

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

 b.修改配置文件

spring.redis.host=192.168.1.125

3.添加测试类

    @Autowired
StringRedisTemplate stringRedisTemplate;//操作字符串【常用】 @Autowired
RedisTemplate redisTemplate;//操作k-v都是对象
@Test
public void test01(){
// stringRedisTemplate.opsForValue().append("msg", "hello");
String msg = stringRedisTemplate.opsForValue().get("msg");
System.out.println(msg);
} 

我们需要做的配置和测试到这里就已经完成了。

并且Spring Boot会在侦测到存在Redis的依赖并且Redis的配置是可用的情况下,还可以使用RedisCacheManager初始化CacheManager。

3、保存对象

    • 如果要直接保存对象,需要使用JDK序列化机制,现将对象序列化后再近些保存Redis中。
    • 将对象转换成JSON格式,存储到Redis中。
      • 第一种方式:自己将对象转换成JSON。(fastJson)
      • 第二种方式:新建一个Redis的配置类MyRedisConfig。(redisTemplate中默认改变的序列化规则)
@Configuration
public class MyRedisConfig {
@Bean
public RedisTemplate<Object, Employee> empRedisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Employee> template = new RedisTemplate<Object, Employee>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer<Employee> jsonRedisSerializer = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
template.setDefaultSerializer(jsonRedisSerializer);
return template;
}

SpringBoot(七) SpringBoot中的缓存机制的更多相关文章

  1. SpringBoot(七)-SpringBoot JPA-Hibernate

    步骤 1.在pom.xml添加mysql,spring-data-jpa依赖2.在application.properties文件中配置mysql连接配置文件3.在application.proper ...

  2. springboot(七).springboot整合jedis实现redis缓存

    我们在使用springboot搭建微服务的时候,在很多时候还是需要redis的高速缓存来缓存一些数据,存储一些高频率访问的数据,如果直接使用redis的话又比较麻烦,在这里,我们使用jedis来实现r ...

  3. hibernate中的缓存机制

    一.为什么要用Hibernate缓存? Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数据源中的数 ...

  4. java整形中的缓存机制

      英文原文:Java Integer Cache 翻译地址:Java中整型的缓存机制 原文作者:Java Papers 翻译作者:Hollis 转载请注明出处. 本文将介绍Java中Integer的 ...

  5. php中ob缓存机制

    1.ob缓存运行方式 2.注意:在程序中如果开启ob_start(),所有的echo输出都会保存到ob缓存中,可以使用ob系列函数进行操作,如果没有,默认情况下,在程序执行结束,会把缓存中的数据发送给 ...

  6. 分享知识-快乐自己:论Hibernate中的缓存机制

    Hibernate缓存 缓存: 是计算机领域的概念,它介于应用程序和永久性数据存储源之间. 缓存: 一般人的理解是在内存中的一块空间,可以将二级缓存配置到硬盘.用白话来说,就是一个存储数据的容器.我们 ...

  7. 解决EF 4.0 中数据缓存机制

    EF4.0默认开启缓存机制,如果想要禁用缓存机制的话,则须加上一句话:_db.CreateObjectSet().MergeOption = MergeOption.OverwriteChanges; ...

  8. 一次读懂mybatis中的缓存机制

    缓存功能针对于查询(没听说果UPDATE,INSERT语句要缓存什么,都是直接执行的) 默认情况下,mybatis会启用一级缓存. 如果使用同一个session对象调用了相同的SELECT语句,则直接 ...

  9. springBoot项目mybatis中加入缓存

    1:maven: <!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache-core --> <dependenc ...

随机推荐

  1. SQL Server-聚焦过滤索引提高查询性能

    前言 这一节我们还是继续讲讲索引知识,前面我们讲了聚集索引.非聚集索引以及覆盖索引等,在这其中还有一个过滤索引,通过索引过滤我们也能提高查询性能,简短的内容,深入的理解,Always to revie ...

  2. https://coderwall.com/p/7smjkq/multiple-ssh-keys-for-different-accounts-on-github-or-gitlab

    Multiple SSH keys for different accounts on Github or Gitlab SSH GIT GITLAB GITHUB Sometimes you nee ...

  3. 构造定律(constructal law)-构造定律作为第二个时间箭头,将和热力学第二定律一道将宇宙推向无序。

    优化系统结构,使信息和物质流在结构内的流动更畅通. 构造定律(constructal law) 由Adrian Bejan于1995创立的构造定律(constructal law):   For a ...

  4. C# DataTable 转 json

    public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { //窗体 ...

  5. java 读取配置文件(nx就转了)

    借鉴别人的 package test; import java.io.FileInputStream; import java.io.FileNotFoundException; import jav ...

  6. Sublime Text 3 Build 3047 安装/插件安装/C编程环境配置

    Sublime Text 3 Build 3047 安装 参考:http://sublimetext.iaixue.com/forum.php?mod=viewthread&tid=29 插件 ...

  7. Dynamics CRM Online 快速的debug 方法

    这里的前提想大家了解一下.  Dynamics 365 online的产品的session是30分钟 timeout. 如果你logout之后, session还是会储存在服务器端不会release. ...

  8. 企业级任务调度框架Quartz(1) --企业应用中的任务调度介绍

    由于目前的工作内容为建行CLPM批处理业务的设计工作,所以很好的理解批处理所用的任务调度框架Quartz势在必行:为了能够更好的去服务于工作,也 为了提升自己,所以我学习了Quartz Job Sch ...

  9. PHP迭代器的内部执行过程

    下面我们来了解如何实现一个自定义的迭代器,然后再开始慢慢理解迭代器的内部工作原理.先来看一个官方的例子: class myIterator implements Iterator { private ...

  10. Python爬虫3-----浏览器伪装

    1.浏览器伪装技术原理 当爬取CSDN博客时,会发现返回403,因为对方服务器会对爬虫进行屏蔽,故需伪装成浏览器才能爬取.浏览器伪装一般通过报头进行. 2.获取网页的报头 3.代码: import u ...