Redis 在 Spring 中的其他用法

RedisTemplate 实现缓存(通常用这个)

1.修改CoffeeService

public class CoffeeService {


    private static final String CACHE = "springbucks-coffee";
    @Autowired
    private CoffeeRepository coffeeRepository;
    @Autowired
    private RedisTemplate<String, Coffee> redisTemplate;

    public List<Coffee> findAllCoffee() {
        return coffeeRepository.findAll();
    }

    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 matcher = ExampleMatcher.matching()
                .withMatcher("name", exact().ignoreCase());
        Optional<Coffee> coffee = coffeeRepository.findOne(
                Example.of(Coffee.builder().name(name).build(), matcher));
        log.info("Coffee Found: {}", coffee);
        if (coffee.isPresent()) {
            log.info("Put coffee {} to Redis.", name);
            hashOperations.put(CACHE, name, coffee.get());//coffee.get() 如果Optional有值则将其返回,否则抛出NoSuchElementException
            redisTemplate.expire(CACHE, 1, TimeUnit.MINUTES); //设置一分钟的过期时间
        }
        return coffee;
    }
}

2.执行SpringBucksApplication

@Slf4j
@EnableTransactionManagement
@SpringBootApplication
@EnableJpaRepositories
public class SpringBucksApplication implements ApplicationRunner {
	@Autowired
	private CoffeeService coffeeService;

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

	@Bean
	public RedisTemplate<String, Coffee> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		RedisTemplate<String, Coffee> template = new RedisTemplate<>();  //因为本来的泛型为object 所以需要我们重新写个
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean
	public LettuceClientConfigurationBuilderCustomizer customizer() {
		return builder -> builder.readFrom(ReadFrom.MASTER_PREFERRED);  //优先读主节点
	}

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

Redis Repository 实现缓存(需要二级索引的时候,用这个)

实体注解

  • @RedisHash
    @RedisHash(value = “springbucks-coffee”, timeToLive = 60)
    对应了@entity,value为名字,ttl为存在周期
  • @Id
    主键
  • @Indexed
    此注解为某个字段申请索引 如果需要二级索引,加这个

代码实现
1.将money转换类改为这两个类


@ReadingConverter   //读Redis数据时候使用这个
public class BytesToMoneyConverter implements Converter<byte[], Money> {
    @Override
    public Money convert(byte[] source) {
        String value = new String(source, StandardCharsets.UTF_8);
        return Money.ofMinor(CurrencyUnit.of("CNY"), Long.parseLong(value));
    }
}
@WritingConverter   ////写入Redis数据时候使用这个
public class MoneyToBytesConverter implements Converter<Money, byte[]> {
    @Override
    public byte[] convert(Money source) {
        String value = Long.toString(source.getAmountMinorLong());
        return value.getBytes(StandardCharsets.UTF_8);
    }
}

2.加入我们需要缓存的Redis实体

@RedisHash(value = "springbucks-coffee", timeToLive = 60)  //对应了entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CoffeeCache {
    @Id
    private Long id;
    @Indexed  //此注解为某个字段申请索引    二级索引
    private String name;
    private Money price;
}

3.加入缓存接口

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

4.修改CoffeeService类

@Slf4j
@Service
public class CoffeeService {
    @Autowired
    private CoffeeRepository coffeeRepository;
    @Autowired
    private CoffeeCacheRepository cacheRepository;

    public List<Coffee> findAllCoffee() {
        return coffeeRepository.findAll();
    }

    public Optional<Coffee> findSimpleCoffeeFromCache(String name) {
        Optional<CoffeeCache> cached = cacheRepository.findOneByName(name);  //Optional类的Javadoc描述如下:这是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,
        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 -> {   //如果Optional实例有值则为其调用consumer,否则不做处理   如果Optional实例有值,调用ifPresent()可以接受接口段或lambda表达式。
                CoffeeCache coffeeCache = CoffeeCache.builder()
                        .id(c.getId())
                        .name(c.getName())
                        .price(c.getPrice())
                        .build();
                log.info("Save Coffee {} to cache.", coffeeCache);
                cacheRepository.save(coffeeCache);
            });
            return raw;
        }
    }

    public Optional<Coffee> findOneCoffee(String name) {
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("name", exact().ignoreCase());
        Optional<Coffee> coffee = coffeeRepository.findOne(
                Example.of(Coffee.builder().name(name).build(), matcher));
        log.info("Coffee Found: {}", coffee);
        return coffee;
    }
}

5.执行SpringBucksApplication

@Slf4j
@EnableTransactionManagement
@SpringBootApplication
@EnableJpaRepositories
@EnableRedisRepositories
public class SpringBucksApplication implements ApplicationRunner {
	@Autowired
	private CoffeeService coffeeService;

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

	@Bean
	public LettuceClientConfigurationBuilderCustomizer customizer() {
		return builder -> builder.readFrom(ReadFrom.MASTER_PREFERRED); //从主节点开始读
	}

	@Bean
	public RedisCustomConversions redisCustomConversions() {
		return new RedisCustomConversions(
				Arrays.asList(new MoneyToBytesConverter(), new BytesToMoneyConverter()));//加入对于金额的处理
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		Optional<Coffee> c = coffeeService.findSimpleCoffeeFromCache("mocha");
		log.info("Coffee {}", c);

		for (int i = 0; i < 5; i++) {
			c = coffeeService.findSimpleCoffeeFromCache("mocha");
		}

		log.info("Value from Redis: {}", c);
	}
}

用Redis实现缓存的方法

  1. 用spring的配置文件
    spring.cache.type=redis
    spring.cache.cache-names=coffee
    spring.cache.redis.time-to-live=5000
    #缓存的生命周期
    spring.cache.redis.cache-null-values=false

  2. RedisTemplate 实现缓存

  3. Redis Repository 实现缓存(需要二级索引使用这个)

RedisTemplate是万能的,各种情况下都能用,不过是手工操作的;@Cachable用在把某个方法的返回值缓存的情况,可以不用自己写,Spring替你做了,这个就会比较方便。Repository这个就比较少用到,像操作数据库的Repository一样来操作Redis,如果针对一些数据有二级索引的需求,Repository替我们做了主键以外的索引。

发布了59 篇原创文章 · 获赞 6 · 访问量 969

猜你喜欢

转载自blog.csdn.net/weixin_43790623/article/details/103326180