Springboot(九)Springboot cache使用和原理

目录

一、搭建基本环境

二、快速体验缓存@Cacheable

三、@Cacheable运行原理

第一步、自动配置类

​​​​​​​第二步、从缓存的配置类 中获取 多个cache​​​​​​​

第三步:SimpleCacheConfiguration.cacheManager()

第四步:查看获取缓存方法getCache()

四、@Cacheable运行流程

五、@Cacheable其它属性

六、@Cacheput

七、@CacheEvict

八、@Caching&@CacheConfig


  • 一、搭建基本环境

1、导入数据库文件 创建出department和employee表
2、创建javaBean封装数据
3、整合MyBatis操作数据库
     1.配置数据源信息
     2.使用注解版的MyBatis;
       1)、@MapperScan指定需要扫描的mapper接口所在的包

application.properties配置数据源信息

spring.datasource.url=jdbc:mysql://localhost:3306/spring_cache
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# 开启驼峰命名匹配规则
mybatis.configuration.map-underscore-to-camel-case=true

logging.level.com.atguigu.cache.mapper=debug

debug=true

spring.redis.host=118.24.44.169
@MapperScan("com.atguigu.cache.mapper")
@SpringBootApplication
public class Springboot01CacheApplication {

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

​​​​​​​

@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);

    @Delete("DELETE FROM employee WHERE id=#{id}")
    public void deleteEmpById(Integer id);

    @Insert("INSERT INTO employee(lastName,email,gender,d_id) VALUES(#{lastName},#{email},#{gender},#{dId})")
    public void insertEmployee(Employee employee);

    @Select("SELECT * FROM employee WHERE lastName = #{lastName}")
    Employee getEmpByLastName(String lastName);
}

测试一下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot01CacheApplicationTests {
	@Autowired
	EmployeeMapper employeeMapper;
@Test
	public void contextLoads() {
		Employee empById = employeeMapper.getEmpById(2);
		System.out.println(empById);
	}

}

​​​​​​​

  • 二、快速体验缓存@Cacheable

步骤:
        1、开启基于注解的缓存 @EnableCaching
        2、标注缓存注解即可
           @Cacheable
           @CacheEvict
           @CachePut
 默认使用的是ConcurrentMapCacheManager==ConcurrentMapCache;将数据保存在   ConcurrentMap<Object, Object>中
 开发中使用缓存中间件;redis、memcached、ehcache;
@MapperScan("com.atguigu.cache.mapper")
@SpringBootApplication
@EnableCaching
public class Springboot01CacheApplication {
	public static void main(String[] args) {
		SpringApplication.run(Springboot01CacheApplication.class, args);
	}
}

EmployeeService中

/**   
 将方法的运行结果进行缓存;以后再要相同的数据,直接从缓存中获取,不用调用方法;
CacheManager管理多个Cache组件的,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字;
        几个属性:
           cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
     
           key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值  1-方法的返回值
                   编写SpEL; #i d;参数id的值   #a0  #p0  #root.args[0]
                  getEmp[2]
     
           keyGenerator:key的生成器;可以自己指定key的生成器的组件id
                   key/keyGenerator:二选一使用;
     
     
           cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
     
           condition:指定符合条件的情况下才缓存;
                   ,condition = "#id>0"
               condition = "#a0>1":第一个参数的值》1的时候才进行缓存
    
           unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
                   unless = "#result == null"
                   unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
           sync:是否使用异步模式
*/
@Cacheable(cacheNames = {"emp"})
    public Employee getEmp(Integer id){
        System.out.println("查询"+id+"号员工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }
  • ​​​​​​​三、@Cacheable运行原理

第一步、自动配置类

自动启动类:CacheAutoConfiguration

​ 属性配置:CacheProperties

​ 主启动类添加:@EnableCaching注解

cache POM添加:

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


​​​​​​​第二步、从缓存的配置类 中获取 多个cache

CacheConfigurationImportSelector.selectImports()方法获取

 

        org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
        org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
        org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
        org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
        org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
        org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
        org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
        org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
        org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration
        org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】
        org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
        3、哪个配置类默认生效:SimpleCacheConfiguration;

第三步:SimpleCacheConfiguration.cacheManager()

此方法中给容器中注册了一个CacheManager组件:类型为ConcurrentMapCacheManager

@Bean
public ConcurrentMapCacheManager cacheManager() {
   ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
   List<String> cacheNames = this.cacheProperties.getCacheNames();
   if (!cacheNames.isEmpty()) {
      cacheManager.setCacheNames(cacheNames);
   }
   return this.customizerInvoker.customize(cacheManager);
}

第四步:查看获取缓存方法getCache()

ConcurrentMapCacheManager 类里,数据都存储到为ConcurrentMap 中

public Cache getCache(String name) {
   Cache cache = this.cacheMap.get(name); //cacheMap 为ConcurrentMap  类型,获取一个cache组件
   if (cache == null && this.dynamic) {
      synchronized (this.cacheMap) {
         cache = this.cacheMap.get(name); //cahceMap不为空获取
         if (cache == null) {
            //可以获取或者创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中;
            cache = createConcurrentMapCache(name);   
            this.cacheMap.put(name, cache); //ConcurrentMapCache.lookup();
         }
      }
   }
   return cache;
}
  • 四、@Cacheable运行流程

1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
      (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
      key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key;
          SimpleKeyGenerator生成key的默认策略;
                  如果没有参数;key=new SimpleKey();
                  如果有一个参数:key=参数的值
                  如果有多个参数:key=new SimpleKey(params);
3、没有查到缓存就调用目标方法;
4、将目标方法返回的结果,放进缓存中

   @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
   如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;

   核心:
      1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
      2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator
  • 五、@Cacheable其它属性

cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
     
           key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值  1-方法的返回值
                   编写SpEL; #i d;参数id的值   #a0  #p0  #root.args[0]
                  getEmp[2]
     
           keyGenerator:key的生成器;可以自己指定key的生成器的组件id
                   key/keyGenerator:二选一使用;
     
     
           cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
     
           condition:指定符合条件的情况下才缓存;
                   ,condition = "#id>0"
               condition = "#a0>1":第一个参数的值》1的时候才进行缓存
    
           unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
                   unless = "#result == null"
                   unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
           sync:是否使用异步模式

    @Cacheable(value = {"emp"},key="#root.methodname+'['+#id+']'")
    public Employee getEmp(Integer id){
        System.out.println("查询"+id+"号员工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }

使用自己指定key的生成器

编写类MyCacheConfig

@Configuration
public class MyCacheConfig {

    @Bean("myKeyGenerator")
    public KeyGenerator keyGenerator(){
        return new KeyGenerator(){

            @Override
            public Object generate(Object target, Method method, Object... params) {
                return method.getName()+"["+ Arrays.asList(params).toString()+"]";
            }
        };
    }
}
    @Cacheable(value = {"emp"},keyGenerator = "myKeyGenerator")
    public Employee getEmp(Integer id){
        System.out.println("查询"+id+"号员工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }

 

  • 六、@Cacheput

EmployService

    /**
     * @CachePut:既调用方法,又更新缓存数据;同步更新缓存
     * 修改了数据库的某个数据,同时更新缓存;
     * 运行时机:
     *  1、先调用目标方法
     *  2、将目标方法的结果缓存起来
     *
     * 测试步骤:
     *  1、查询1号员工;查到的结果会放在缓存中;
     *          key:1  value:lastName:张三
     *  2、以后查询还是之前的结果
     *  3、更新1号员工;【lastName:zhangsan;gender:0】
     *          将方法的返回值也放进缓存了;
     *          key:传入的employee对象  值:返回的employee对象;
     *  4、查询1号员工?
     *      应该是更新后的员工;
     *          key = "#employee.id":使用传入的参数的员工id;
     *          key = "#result.id":使用返回后的id
     *             @Cacheable的key是不能用#result
     *      为什么是没更新前的?【1号员工没有在缓存中更新】
     *
     */
    @CachePut(value = "emp",key = "#result.id")
    public Employee updateEmp(Employee employee){
        System.out.println("updateEmp:"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }

 

  • 七、@CacheEvict

    /**
     * @CacheEvict:缓存清除
     *  key:指定要清除的数据
     *  allEntries = true:指定清除这个缓存中所有的数据
     *  beforeInvocation = false:缓存的清除是否在方法之前执行
     *      默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
     *
     *  beforeInvocation = true:
     *      代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
     *
     *
     */
    @CacheEvict(value="emp",beforeInvocation = true,key = "#id")
    public void deleteEmp(Integer id){
        System.out.println("deleteEmp:"+id);
        //employeeMapper.deleteEmpById(id);
        int i = 10/0;
    }

 

  • 八、@Caching&@CacheConfig

有时候我们可能组合多个Cache注解使用,此时就需要@Caching组合多个注解标签了。

    // @Caching 定义复杂的缓存规则
    @Caching(
         cacheable = {
             @Cacheable(/*value="emp",*/key = "#lastName")
         },
         put = {
             @CachePut(/*value="emp",*/key = "#result.id"),
             @CachePut(/*value="emp",*/key = "#result.email")
         }
    )

当我们需要缓存的地方越来越多,你可以使用@CacheConfig(cacheNames = {"myCache"})注解来统一指定value的值,这时可省略value,如果你在你的方法依旧写上了value,那么依然以方法的value值为准。

使用方法如下:

@CacheConfig(cacheNames = {"myCache"})
public class BotRelationServiceImpl implements BotRelationService {
    @Override
    @Cacheable(key = "targetClass + methodName +#p0")//此处没写value
    public List<BotRelation> findAllLimit(int num) {
        return botRelationRepository.findAllLimit(num);
    }
    .....
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 3.0 目前还没有正式发布,所以还不能确定它是否添加了对 Jetcache 的官方支持。但是,你可以在你的 Spring Boot 项目中手动集成 Jetcache。 要在 Spring Boot 项目中使用 Jetcache,首先需要添加 Jetcache 的相关依赖。你可以在 Maven 或者 Gradle 的配置文件中添加以下依赖: Maven: ```xml <dependency> <groupId>com.alicp.jetcache</groupId> <artifactId>jetcache-starter-redis</artifactId> <version>2.6.0</version> </dependency> ``` Gradle: ``` compile group: 'com.alicp.jetcache', name: 'jetcache-starter-redis', version: '2.6.0' ``` 上述依赖是使用 Redis 作为缓存后端的示例,如果你想使用其他的缓存后端,可以根据需要选择不同的依赖。 接下来,你需要在你的 Spring Boot 配置文件中配置 Jetcache 的相关信息。以下是一个示例配置: ```yaml spring: jetcache: enabled: true remote: server-addrs: redis://localhost:6379 ``` 这个示例配置将启用 Jetcache,并将 Redis 作为缓存后端。 最后,在你的代码中使用 `@Cached` 注解来标记需要缓存的方法,例如: ```java import com.alicp.jetcache.anno.Cached; @Cached(name = "myCache", expire = 3600) public String getData(String key) { // 从数据库或其他数据源获取数据的逻辑 // ... } ``` 这样,`getData` 方法的返回值将被缓存起来,下次调用时可以直接从缓存中获取,而不需要执行方法体。 这只是一个简单的示例,你可以根据实际需求配置更多的缓存策略和选项。Jetcache 提供了丰富的功能和选项,你可以参考 Jetcache 的官方文档以获取更多详细信息和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值