SpringCache 缓存

csdn推荐

目录

SpringCache 缓存 环境配置 1)依赖如下

父依赖 SpringBoot 3.2.5

        
            org.springframework.boot
            spring-boot-starter-cache
        

2)配置文件

spring:
  cache:
    type: redis
    redis:
      time-to-live: 3600000
      # key-prefix: CACHE_
      use-key-prefix: true 
      cache-null-values: true

3)设置缓存的 value 序列化为 JSON 格式

import org.springframework.boot.autoconfigure.cache.CacheProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
import org.springframework.data.redis.serializer.RedisSerializationContext
import org.springframework.data.redis.serializer.StringRedisSerializer
@Configuration
@EnableConfigurationProperties(CacheProperties::class) //让配置文件中的配置生效
@EnableCaching // 开启 SpringCache 缓存功能(如果这里不写这个注解,启动类上也一定要有!!!)
class MyCacheConfig {
    @Bean
    fun redisCacheConfiguration(
        cacheProperties: CacheProperties
    ): RedisCacheConfiguration {
        //这里源码怎么写,咱们咱们写(只需要改一下缓存 value 的序列化方式即可)
        var config = RedisCacheConfiguration.defaultCacheConfig()
        //设置 key value 的序列化方式
        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(GenericJackson2JsonRedisSerializer()))
        val redisProperties = cacheProperties.redis
        //将配置文件中的所有配置都生效
        redisProperties.timeToLive?.let {
            config = config.entryTtl(it)
        }
        redisProperties.keyPrefix?.let {
            config = config.prefixCacheNameWith(it)
        }
        if (!redisProperties.isCacheNullValues) {
            config = config.disableCachingNullValues()
        }
        if (!redisProperties.isUseKeyPrefix) {
            config = config.disableKeyPrefix()
        }
        return config
    }
}

4)@EnableCaching

@EnableCaching 表示开启 SpringCache 缓存功能,加在 启动类 或者 配置类 上都可以.

实战开发 @Cacheable

a)使用说明:

@Cacheable 用来将方法的返回值数据保存到缓存中.

常用属性如下:

key:指定 key 是什么. 接受一个 SpEL 表达式,例如如下表格中的示例

condition:条件判断属性,只有符合条件才可以被缓存. sync:是否为同步执行. 如果设置为 true,会加锁(本地锁),可以用来解决击穿问题.

b)案例如下:

例如通过 SpEL表达式设置 缓存的 key 为 动态的id + "userinfo" ,

    @Cacheable(value = ["user"], key = "#id + 'userinfo'")
    override fun getUserinfo(id: Long): UserinfoVo {
        //业务逻辑...
        println("查询数据库...")
        return UserinfoVo( // 这里的 UserinfoVo 必须要有无参构造才行,否则缓存将来读取的时候会报错
            id = id,
            name = "cyk",
            age = 21,
        )
    }

第一查询之后,就可以看到 Redis 上面已经存在该数据. 之后的只要缓存未过期,都会直接查缓存.

@CacheEvict

a)使用说明

@CacheEvict 用来将数据从缓存中删除.

他常常被用来实现 “失效模式” 来解决缓存一致性问题(数据库中的数据被更新之后,直接删除缓存上的数据即可,下次查询的时候,自动同步到缓存上).

常用属性和@Cacheable 差不多,这里不再赘述.

b)案例如下

例如实现缓存失效:现在要进行用户信息的修改,那么为了保证缓存和数据库中数据一致,修改完数据库之后的就直接删除对应的缓存数据即可~ 下次查询时,再更新缓存.

这里通过 SpEL 表达式设置要删除的缓存的 key 为 动态的id + "userinfo" ,

    /**
     *  通过 @CacheEvict 实现缓存失效,下次查询时,再更新缓存
     */
    @CacheEvict(value = ["user"], key = "#dto.id + 'userinfo'")
    override fun updateUserinfo(dto: UserinfoDto) {
        //业务逻辑...
        println("修改数据库数据...")
    }

另外,还可以通过 属性,删除同一个分区下的所有缓存(慎用)

@CacheEvict(value = ["user"],  allEntries = true)

@CachePut

a)使用说明

@CachePut 用来更新缓存数据.

与 @Cacheable 不同的是,使用 @CachePut 标注的方法在执行前不会检查缓存中是否存在这个数据,而是每次都会执行这个方法,并将返回值写入到缓存中.

属性上和 @Cacheable 是一样的,这里不再赘述.

b)案例如下

    @CachePut(value = ["user"], key = "#dto.id + 'userinfo'")
    override fun putUserinfo(dto: UserinfoDto): UserinfoVo {
        //业务逻辑
        println("更新数据库...")
        return with(dto) {
            UserinfoVo(
                id = id,
                name = name,
                age = age,
            )
        }
    }

@Caching

@Caching 用来组合以上多个操作.

例如删除同时删除多个缓存数据

    @Caching(evict = [
        CacheEvict(value = ["user"], key = "#dto.id + 'userinfo'"),
        CacheEvict(value = ["user"], key = "#dto.id + 1 + 'userinfo'"),
    ])
    override fun updateUserinfo(dto: UserinfoDto) {
        //业务逻辑...
        println("修改数据库数据...")
    }

@CacheConfig

如果一个类中有很多一样的 cacheName、keyGenerator、cacheManager、cacheResolver,可以直接使用 @CacheConfig 在类上声明,那么这个类中的所有标记了 Cache 相关注解的方法都会共享@CacheConfig 属性

@Service
//@CacheConfig(cacheNames = ["aaa", "bbb"]) 会创建两个缓存分区, aaa 和 bbb
@CacheConfig(cacheNames = ["user"])
class CacheServiceImpl: CacheService {
    @Cacheable(key = "#id + 'userinfo'")
    override fun getUserinfo(id: Long): UserinfoVo {
        //业务逻辑...
        println("查询数据库...")
        return UserinfoVo( // 这里的 UserinfoVo 必须要有无参构造才行,否则缓存将来读取的时候会报错
            id = id,
            name = "cyk",
            age = 21,
        )
    }
    /**
     *  通过 @CacheEvict 实现缓存失效,下次查询时,再更新缓存
     */
    @CacheEvict(key = "#dto.id + 'userinfo'")
    override fun updateUserinfo(dto: UserinfoDto) {
        //业务逻辑...
        println("修改数据库数据...")
    }
    @CachePut(key = "#dto.id + 'userinfo'")
    override fun putUserinfo(dto: UserinfoDto): UserinfoVo {
        //业务逻辑
        println("更新数据库...")
        return with(dto) {
            UserinfoVo(
                id = id,
                name = name,
                age = age,
            )
        }
    }
}

SpringCache 的优势和劣势 读操作(优势)

SpringCache 在读操作上的处理的还是很到位的:

写操作(劣势) 总结

对于读多写少,一致性要求不高的数据,完全可以使用 SpringCache 来简化开发(只要缓存的数据有过期时间就可以).

对于一致性要求高的场景,也没必要引入引入缓存,直接对数据库进行读写即可.

特殊数据特殊处理.

文章来源:https://blog.csdn.net/CYK_byte/article/details/139475724



微信扫描下方的二维码阅读本文

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容