RedisTemplate与RedisRepository-Spring入门学习笔记16

本文介绍了Spring中RedisTemplate和RedisRepository的使用,重点讲解了它们在缓存场景下的区别。RedisTemplate提供基本的Redis操作,适合简单缓存需求,而RedisRepository支持二级索引,便于按不同维度查询。通过实例展示了如何配置和使用这两个工具,包括CoffeeService中的缓存逻辑,并探讨了主键和非主键索引在查询效率上的差异。
摘要由CSDN通过智能技术生成

第九天

RedisTemplate与RedisRepository

两者的应用场景的区别,

比如,你按ID存了一个数据到Redis里,但又希望能按别的维度来查询时,一种方式就是自己维护二级索引,而RedisRepository可以帮你做这个二级索引,让你根据自己需要来查询。

完全自己用Jedis或者Lettuce客户端什么都做,也就是你说的最灵活的。但如果你就想缓存一些方法的执行结果,Spring的缓存抽象都帮你写好了,直接用就行,这时你就不用自己再操心怎么写了

简单来说,就是RedisTemplate就是封装好的,直接操作就可以用的;RedisRepository要求对细节上有更多的控制

RedisTemplate

引入依赖后

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

就在CoffeeService类中、注入RedisTemplate、写一个findOneCoffee方法

    @Autowired
    private RedisTemplate<String, Coffee> redisTemplate;
    
    public Optional<Coffee> findOneCoffee(String name) {
    //omit
    }

在Optional findOneCoffee(String name)方法中

    //redis缓存名称
    private static final String CACHE="springbucks-coffee";
    //findOneCoffee方法
    public Optional<Coffee> findOneCoffee(String name) {
        HashOperations<String, String, Coffee> hashOperations = redisTemplate.opsForHash();
        if (redisTemplate.hasKey(CACHE) && hashOperations.hasKey(CACHE, name)) {
            log.info("Get coffee {} from Redis.", name);
            return Optional.of(hashOperations.get(CACHE, name));
        }
        ExampleMatcher exampleMatcher=ExampleMatcher.matching().withMatcher("name",exact().ignoreCase());
        Optional<Coffee> coffee=coffeeRepository.findOne(Example.of(Coffee.builder().name(name).build(),exampleMatcher));
        log.info("Coffee Found: {}", coffee);
        if(coffee.isPresent()){
            log.info("Put coffee {} to Redis.", name);
            hashOperations.put(CACHE,name,coffee.get());
            //设置过期时间
            redisTemplate.expire(CACHE,1, TimeUnit.MINUTES);
        }
        return coffee;
    }

使用的入口类开启事务注解,注入CoffeeService的Bean,就可以简单通过RedisTemplate为方法findOneCoffee使用缓存

    ···
@EnableTransactionManagement
public class RedisApplication implements ApplicationRunner {
    @Autowired
    private CoffeeService coffeeService;
    ···
    @Bean
    public RedisTemplate<String, Coffee>redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String,Coffee> template=new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    ···
    @Override
    public void run(ApplicationArguments args) throws Exception{
        Optional<Coffee> c = coffeeService.findOneCoffee("mocha");
        log.info("Coffee {}", c);

        for(int i=0;i<5;i++){
            c=coffeeService.findOneCoffee("mocha");
        }
        log.info("Value from Redis: {}", c);
    }

RedisRepository

先新建一个CoffeeCache类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@RedisHash(value = "springbucks-coffee",timeToLive = 60)//指定redis命名及ttl时间
public class CoffeeCache {
    @Id
    private Long id;
    @Indexed
    private String name;
    private Money price;
}

而后

public interface CoffeeCacheRepository extends CrudRepository<CoffeeCache, Long> {
    Optional<CoffeeCache> findOneByName(String name);
}

在CoffeeService中注入repository

    @Autowired
    private CoffeeCacheRepository coffeeCacheRepository;
    
    public Optional<Coffee> findSimpleCoffeeFromCache(String name) {

        Optional<CoffeeCache> cached = coffeeCacheRepository.findOneByName(name);
        if (cached.isPresent()) {
            CoffeeCache coffeeCache = cached.get();
            Coffee coffee = Coffee.builder().name(coffeeCache.getName()).price(coffeeCache.getPrice()).build();
            log.info("Coffee {} found in cache.", coffeeCache);
            return Optional.of(coffee);
        }
        else{
            Optional<Coffee> raw=findOneCoffee(name);
            raw.ifPresent(c->{
                CoffeeCache coffeeCache=CoffeeCache.builder().id(c.getId()).name(c.getName()).price(c.getPrice()).build();
                log.info("Save Coffee {} to cache.", coffeeCache);
                coffeeCacheRepository.save(coffeeCache);
            });
            return raw;
        }

在application类中注入

    @Autowired
    private CoffeeService coffeeService;

直接调用
findSimpleCoffeeFromCache
方法即可

扩展内容

@Indexed
用于标识对应属性在Redis数据库中生成二级索引。使用该注解后会在Redis数据库中生成属性对应的二级索引,索引名称就是属性名,可以方便地进行数据条件查询

主键索引和非主键索引的区别是:非主键索引的叶子节点存放的是主键的值,而主键索引的叶子节点存放的是整行数据,其中非主键索引也被称为二级索引,而主键索引也被称为聚簇索引。

根据这两种结构我们来进行下查询,看看他们在查询上有什么区别。

1、如果查询语句是 select * from table where ID = 100,即主键查询的方式,则只需要搜索 ID 这棵 B+树。

2、如果查询语句是 select * from table where k = 1,即非主键的查询方式,则先搜索k索引树,得到ID=100,再到ID索引树搜索一次,这个过程也被称为回表。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值