栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

SpringBoot 应用 Redis 声明式缓存

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot 应用 Redis 声明式缓存

什么是声明式缓存 ?

Spring 框架提供一种抽象的缓存机制,且 Spring 只提供接口,不提供缓存的具体实现。所以在程序中使用时,需要有具体缓存的实现。目前支持的常见的缓存比如 JDK ConcurrentMap-based Cache、Ehcache、Redis、Caffeine Cache、Guava Cache 等。

所谓声明式缓存,即使用 Spring 框架提供的注解来使用缓存功能。这就需要知道一些常用的注解:

  • @EnableCaching

Spring 默认没有开启缓存注解支持,可以在配置类上使用该注解进行开启。

  • @Cacheable

程序在执行方法时首先会去缓存中检查 key 对应的 value 是否存在。如果存在,则方法体不再执行,直接取缓存中的 value 返回;否则执行方法体,并将方法的返回值进行缓存。@Cacheable 注解的使用倾向于减少方法的执行。

  • @CachePut

方法执行完毕之后,将返回值 update 或者 insert 到缓存中。

  • @CacheEvict

方法执行完毕之后,将缓存删除。

更多关于 Spring 框架缓存注解的说明可以参考官方文档:Spring Boot Caching

测试环境说明
  • SpringBoot版本:2.0.2.RELEASE

  org.springframework.boot
  spring-boot-starter-parent
  2.0.2.RELEASE
  

  • Redis 版本:3.2.9,pom 依赖:

  org.springframework.boot
  spring-boot-starter-data-redis

  • MySQL 版本:8.0.12,pom 依赖:


  org.springframework.boot
  spring-boot-starter-data-jpa



  org.springframework.boot
  spring-boot-starter-jdbc



  mysql
  mysql-connector-java
  8.0.12
  runtime

  • mock 数据 sql:
-- 测试数据库
CREATE DATAbase IF NOT EXISTS test;

-- 城市信息表
CREATE TABLE IF NOT EXISTS `test`.`city_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增 id',
  `city` varchar(128) NOT NULL DEFAULT '' COMMENT '城市名称',
  `longitude` bigint(20) NOT NULL DEFAULT '0' COMMENT '经度(100倍存储)',
  `latitude` bigint(20) NOT NULL DEFAULT '0' COMMENT '纬度(100倍存储)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='城市信息表';

-- fake 测试数据
INSERT INTO `city_info` (`id`, `city`, `longitude`, `latitude`)
VALUES
	(1, '合肥', 11717, 3152),
	(2, '安庆', 11702, 3031),
	(3, '宿州', 11658, 3338);
测试代码

代码中已经给出了详细的注释说明,且使用方法也比较简单,不做过多解释。

Redis 配置


@EnableCaching      // 启用缓存功能, 默认不启用
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    private final RedisConnectionFactory redisConnectionFactory;

    @Autowired
    public RedisConfig(RedisConnectionFactory redisConnectionFactory) {
 this.redisConnectionFactory = redisConnectionFactory;
    }

    
    @Override
    public CacheManager cacheManager() {

 // 初始化一个 RedisCacheWriter
 // RedisCacheWriter 提供了对 Redis 的 set、setnx、get 等命令的访问权限
 // 可以由多个缓存实现共享,并负责写/读来自 Redis 的二进制数据
 RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);

 // 设置 CacheManager 的值序列化方式
 RedisSerializer jsonSerializer = new JdkSerializationRedisSerializer();
 RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair
  .fromSerializer(jsonSerializer);
 // 提供 Redis 的配置
 RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
  .serializevaluesWith(pair);

 // 设置默认超过期时间是 30 秒
 defaultCacheConfig.entryTtl(Duration.ofSeconds(30));

 // 初始化 RedisCacheManager 返回
 return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
    }

    
    @Override
    public KeyGenerator keyGenerator() {

 return (clazz, method, args) -> {

     StringBuilder sb = new StringBuilder();
     sb.append(clazz.getClass().getName()).append("#");
     sb.append(method.getName()).append("(");
     for (Object obj : args) {
  sb.append(obj.toString()).append(",");
     }
     sb.deleteCharAt(sb.length() - 1);
     sb.append(")");
     return sb.toString();
 };
    }
}

城市信息实体

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "city_info")
public class CityInfo implements Serializable {

    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    
    @Basic
    @Column(name = "city", nullable = false)
    private String city;

    
    @Basic
    @Column(name = "longitude", nullable = false)
    private Long longitude;

    
    @Basic
    @Column(name = "latitude", nullable = false)
    private Long latitude;
}
城市信息服务接口定义

public interface ICityInfoService {

    
    CityInfo getCityInfoById(Long id);

    
    CityInfo updateCityInfo(CityInfo newObj);

    
    void deleteCityInfoById(Long id);
}
城市信息服务接口定义

@Slf4j
@Service
public class CityInfoServiceImpl implements ICityInfoService {

    
    private final CityInfoRepository repository;

    @Autowired
    public CityInfoServiceImpl(CityInfoRepository repository) {
 this.repository = repository;
    }

    
    @Override
    @SuppressWarnings("all")
    @Cacheable(cacheNames = "city_info", key = "#id")
//    @Cacheable(cacheNames = "city_info")
    public CityInfo getCityInfoById(Long id) {

 log.info("get CityInfo by id: {}", id.toString());
 return repository.findById(id).get();
    }

    @Override
    @CachePut(cacheNames="city_info", key="#newObj.id")
    public CityInfo updateCityInfo(CityInfo newObj) {

 log.info("update CityInfo: {}", JSON.toJSONString(newObj));
 return repository.save(newObj);
    }

    @Override
    @CacheEvict(cacheNames = "city_info", key = "#id")
    public void deleteCityInfoById(Long id) {

 log.info("delete CityInfo by id: {}", id.toString());
 repository.deleteById(id);
    }
}
Spring 声明式缓存测试用例

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class CacheAnnotationTest {

    @Autowired
    private ICityInfoService cityInfoService;

    
    @Test
    public void testGetCityInfoById() {

 System.out.println(JSON.toJSONString(cityInfoService.getCityInfoById(1L)));
    }

    
    @Test
    public void testUpdateCityInfo() {

 System.out.println(JSON.toJSONString(cityInfoService.updateCityInfo(
  new CityInfo(1L, "合肥", 11717L, 3153L)
 )));
    }

    
    @Test
    public void testDeleteCityInfoById() {

 cityInfoService.deleteCityInfoById(1L);
    }
}

执行测试用例之后,可以在 Redis 中看到自动生成的缓存 KV:

127.0.0.1:6379> keys *
1) "city_info::1"
2) "city_info::com.imooc.ad.service.impl.CityInfoServiceImpl#getCityInfoById(1)"
127.0.0.1:6379> type city_info::1
string
127.0.0.1:6379> get city_info::1
"xacxedx00x05srx00x1ccom.imooc.ad.entity.CityInfoxe2/O>xd3xe6xeexc8x02x00x04Lx00x04citytx00x12Ljava/lang/String;Lx00x02idtx00x10Ljava/lang/Long;Lx00blatitudeqx00~x00x02Lx00tlongitudeqx00~x00x02xptx00x06xe5x90x88xe8x82xa5srx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x00x00x00x00x00x01sqx00~x00x05x00x00x00x00x00x00x0cPsqx00~x00x05x00x00x00x00x00x00-xc5"
127.0.0.1:6379>

·······························
欢迎关注课程:

基于 SpringCloud 微服务架构下 广告系统设计与实现

JAVA分布式优惠券系统后台 手把手实战开发

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号