本文共 15729 字,大约阅读时间需要 52 分钟。
POM依赖
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-redis org.apache.commons commons-pool2 2.4.3
配置文件
spring.redis.host=localhostspring.redis.port=6379spring.redis.password=xiaobu1994# 连接超时时间(毫秒)spring.redis.timeout=10000# Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0spring.redis.database=0# 连接池最大连接数(使用负值表示没有限制) 默认 8spring.redis.lettuce.pool.max-active=8# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1spring.redis.lettuce.pool.max-wait=-1# 连接池中的最大空闲连接 默认 8spring.redis.lettuce.pool.max-idle=8# 连接池中的最小空闲连接 默认 0spring.redis.lettuce.pool.min-idle=0#缓存配置# 一般来说是不用配置的,Spring Cache 会根据依赖的包自行装配 先后顺序 JCache -> EhCache -> Redis -> Guavaspring.cache.type=redis
启动类
package com.xiaobu;import lombok.extern.slf4j.Slf4j;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cache.annotation.EnableCaching;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import tk.mybatis.spring.annotation.MapperScan;/** * @author xiaobu * @EnableCaching 开启缓存 */@EnableCaching@SpringBootApplication@Slf4jpublic class SsmApplication implements WebMvcConfigurer, CommandLineRunner { public static void main(String[] args) { SpringApplication.run(SsmApplication.class, args); } @Override public void run(String... args) throws Exception { log.info("服务启动成功。。。。"); }}
直接使用
用FastJson实现序列化
package com.xiaobu.base.entity;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.serializer.SerializerFeature;import org.springframework.data.redis.serializer.RedisSerializer;import org.springframework.data.redis.serializer.SerializationException;import java.nio.charset.Charset;/** * @author xiaobu * @version JDK1.8.0_171 * @date on 2019/9/4 17:07 * @description 序列化器 */public class FastJsonRedisSerializerimplements RedisSerializer { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private Class clazz; public FastJsonRedisSerializer(Class clazz) { super(); this.clazz = clazz; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); return (T) JSON.parseObject(str, clazz); }}
自定义序列化使用
package com.xiaobu.config;import com.alibaba.fastjson.parser.ParserConfig;import com.xiaobu.base.entity.FastJsonRedisSerializer;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.cache.CacheManager;import org.springframework.cache.annotation.CachingConfigurerSupport;import org.springframework.cache.annotation.EnableCaching;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.data.redis.cache.RedisCacheConfiguration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.cache.RedisCacheWriter;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.RedisSerializationContext;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;/** * @author xiaobu * @version JDK1.8.0_171 * @date on 2019/9/4 19:25 * @description V1.0 */@Configurationpublic class RedisConfig extends CachingConfigurerSupport { @Bean @Primary//当有多个管理器的时候,必须使用该注解在一个管理器上注释:表示该管理器为默认的管理器 public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { //初始化一个RedisCacheWriter RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); //序列化方式1 //设置CacheManager的值序列化方式为JdkSerializationRedisSerializer,但其实RedisCacheConfiguration默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value,所以以下(4行)注释代码为默认实现// ClassLoader loader = this.getClass().getClassLoader();// JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer(loader);// RedisSerializationContext.SerializationPair
package com.xiaobu;import com.xiaobu.entity.City;import com.xiaobu.mapper.CountryMapper;import com.xiaobu.service.CountryService;import lombok.extern.slf4j.Slf4j;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.test.context.junit4.SpringRunner;import java.util.concurrent.TimeUnit;/** * @author xiaobu * @version JDK1.8.0_171 * @date on 2019/9/4 10:40 * @description V1.0 手动使用redis */@RunWith(SpringRunner.class)@SpringBootTest@Slf4jpublic class RedisTest { @Autowired private CountryMapper countryMapper; @Autowired CountryService countryService; @Autowired private RedisTemplate redisTemplate; @Autowired private StringRedisTemplate stringRedisTemplate; @Test public void test(){ //字符串 stringRedisTemplate.opsForValue().set("name", "小布"); log.info(stringRedisTemplate.opsForValue().get("name")); City city = new City(); city.setName("深圳"); city.setState("广东"); ValueOperationsops = redisTemplate.opsForValue(); ops.set("city1", city); City city1= (City) redisTemplate.opsForValue().get("city1"); log.info("city1 ==> [{}]", city1); //设置过期 ops.set("tempCity",city,1, TimeUnit.HOURS); City tempCity= (City) redisTemplate.opsForValue().get("tempCity"); log.info("tempCity ==> [{}]", tempCity); }}
查看redis,可以看出已经设置成功.
使用Spring Cache自动根据方法生成缓存
key: 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。例如:@Cacheable(value=”testcache”,key=”#id”)
value: 缓存的名称,必须指定至少一个。例如:@Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”}
condition: 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存(如:condition ="#id<2",只缓存id<2的;condition=”#userName.length()>2”只缓存名字长度大于2的)
@Cacheable注解会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存。
@CachePut注解的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用 。简单来说就是用户更新缓存数据。但需要注意的是该注解的value 和 key 必须与要更新的缓存相同,也就是与@Cacheable 相同。
@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空 。
@CacheConfig 一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的。这个时候可以使用@CacheConfig @CacheConfig是一个类级别的注解,允许共享缓存的名称、KeyGenerator、CacheManager 和CacheResolver。
该操作会被覆盖。
控制层
@RequestParam 和 @PathVariable 注解是用于从request中接收请求的,两个都可以接收参数,关键点不同的是@RequestParam 是从request里面拿取值,而 @PathVariable 是从一个URI模板里面来填充
package com.xiaobu.controller;import com.xiaobu.entity.City;import com.xiaobu.service.CityService;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.CachePut;import org.springframework.cache.annotation.Cacheable;import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/** * @author xiaobu * @version JDK1.8.0_171 * @date on 2019/9/4 16:25 * @description */@RestController@RequestMapping("/cache")public class CacheController { @Resource private CityService cityService; /** * 功能描述:只有当id<2是才会缓存 redis的key为 cacheCity::1 http://localhost:8899/cities/getCityByCache/1 * @author xiaobu * @date 2019/7/29 15:12 * @param id id * @return com.xiaobu.entity.City * @version 1.0 */ @Cacheable(value = "cacheCity",key ="#id", condition ="#id<2") @GetMapping("getCityByCache/{id}") public City getCityByCache(@PathVariable Integer id) { return cityService.getCityByCache(id); } /** * 功能描述:把更新后的放入缓存 key为 cacheCity::1 http://localhost:8899/cities/getCityByCachePut/1 * @author xiaobu * @date 2019/9/4 13:41 * @param id id * @return com.xiaobu.entity.City * @version 1.0 */ @CachePut(value = "cacheCity",key = "#id") @GetMapping("getCityByCachePut/{id}") public City getCityByCachePut(@PathVariable Integer id) { return cityService.getCityByCachePut(id); } /** * 功能描述:清除 key为 cacheCity::1的缓存数据 http://localhost:8899/cities/getCityByNoCache/1/xiaobu * @author xiaobu * @date 2019/7/29 15:11 * @param id, name] * @return com.xiaobu.entity.City * @version 1.0 */ @CacheEvict(value = "cacheCity",key = "#id") @GetMapping(value = "getCityByNoCache/{id}") public City getCityByNoCache(@PathVariable Integer id, @RequestParam String name) { System.out.println("id = " + id+",name="+name); return cityService.getCityByNoCache(id); }}
服务层:
/* * The MIT License (MIT) * * Copyright (c) 2014-2016 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */package com.xiaobu.service;import com.github.pagehelper.PageHelper;import com.xiaobu.entity.City;import com.xiaobu.mapper.CityMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.CachePut;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Service;import java.util.List;/** * @author xiaobu * @since 2019-09-04 11:09 */@Servicepublic class CityService { @Autowired private CityMapper cityMapper; public ListgetAll(City city) { if (city.getPage() != null && city.getRows() != null) { PageHelper.startPage(city.getPage(), city.getRows()); } return cityMapper.selectAll(); } public City getById(Integer id) { return cityMapper.selectByPrimaryKey(id); } public void deleteById(Integer id) { cityMapper.deleteByPrimaryKey(id); } public void save(City country) { if (country.getId() != null) { cityMapper.updateByPrimaryKey(country); } else { cityMapper.insert(country); } } @Cacheable(value = "cacheCity",key ="#id", condition ="#id<2") public City getCityByCache(Integer id){ System.out.println("getCityByCache 执行查询。。。。"); return cityMapper.selectByPrimaryKey(id); } @CachePut(value = "cacheCity",key = "#id") public City getCityByCachePut(Integer id){ System.out.println("getCityByCachePut 执行查询。。。。"); City city= cityMapper.selectByPrimaryKey(id); city.setState("广东"); cityMapper.updateByPrimaryKey(city); return city; } @CacheEvict(value = "cacheCity",key = "#id") public City getCityByNoCache(Integer id){ System.out.println("getCityByNoCache 执行查询。。。。"); return cityMapper.selectByPrimaryKey(id); }}
访问 http://localhost:8899/cache/getCityByCache/1 第一次会去数据库查,第二次则直接在缓存里面查找。
访问 http://localhost:8899/cache/getCityByCachePut/1 两次都会去数据库查
先访问 http://localhost:8899/cache/getCityByNoCache/1/xiaobu 会发现缓存被清除了,数据是从数据库重新查的.
参考: