Springboot+redis實現快取機制
阿新 • • 發佈:2020-10-29
SpringBoot專案使用Redis做快取
首先需要安裝redis並啟動,下載連結:http://download.redis.io/releases/redis-4.0.14.tar.gz
1.專案pom檔案引入Cache和Redis依賴
<!-- kaptcha --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2.配置application.properties
## Redis部分 # Redis資料庫索引(預設為0) spring.redis.database=0 # Redis伺服器地址 spring.redis.host=106.14.72.179 # Redis伺服器連線埠 spring.redis.port=6379 # Redis伺服器連線密碼(預設為空) spring.redis.password= # 連線池最大連線數(使用負值表示沒有限制) spring.redis.jedis.pool.max-active=8 # 連線池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.jedis.pool.max-wait=-1ms # 連線池中的最大空閒連線 spring.redis.jedis.pool.max-idle=8 # 連線池中的最小空閒連線 spring.redis.jedis.pool.min-idle=0 # 連線超時時間(毫秒) spring.redis.timeout=5000 ## Cache部分 #快取的名稱集合,多個採用逗號分割 spring.cache.cache-names= #快取的型別,官方提供了很多,這裡我們填寫redis spring.cache.type=redis #是否快取null資料,預設是false spring.cache.redis.cache-null-values=false #redis中快取超時的時間,預設60000ms spring.cache.redis.time-to-live=60000 #快取資料key是否使用字首,預設是true spring.cache.redis.use-key-prefix=true #快取資料key的字首,在上面的配置為true時有效, spring.cache.redis.key-prefix=
3.配置Configuration
package com.example.demo.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.time.Duration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @Configuration public class CacheConfig { @Bean CacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig(); //common資訊快取配置 RedisCacheConfiguration userCacheConfiguration = defaultCacheConfig // 設定 key為string序列化 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // 設定value為json序列化 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())).disableCachingNullValues(); Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(); //entryTtl設定快取失效時間,單位是秒 redisCacheConfigurationMap.put("common", userCacheConfiguration.entryTtl(Duration.ofSeconds(30))); //設定CacheManager的值序列化方式為JdkSerializationRedisSerializer,但其實RedisCacheConfiguration預設就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value,所以以下注釋程式碼為預設實現 //ClassLoader loader = this.getClass().getClassLoader(); //JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer(loader); //RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jdkSerializer); //RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair); Set<String> cacheNames = new HashSet<>(); cacheNames.add("common"); //初始化RedisCacheManager RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory).cacheDefaults(defaultCacheConfig).initialCacheNames(cacheNames).withInitialCacheConfigurations(redisCacheConfigurationMap).build(); return cacheManager; } }
4.啟動類Application或App加@EnableCaching註解
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
5.快取註解的使用
- Cacheable:呼叫方法時先從快取中查詢有沒有對應key的資料,如果有直接從快取獲取返回,如果沒有則執行方法,將返回值存入快取中。
- CacheEvict:呼叫方法後從快取中刪除對應key的資料
- Caching:當一個方法需要查詢多個快取或者刪除多個快取時使用
package com.example.demo.service; import com.example.demo.domain.Blog; import com.example.demo.domain.BlogExample; import com.example.demo.enumdata.EnumBlogType; import com.example.demo.mapper.BlogMapper; import org.apache.commons.lang3.StringUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.List; @Service public class BlogService { @Resource private BlogMapper blogMapper; //unless 引數就是不執行Cacheable的條件 @Cacheable(value = "common", key = "'blog_'+#blogId", unless = "#blogId == null") public Blog getBlogById (Long blogId) { return blogMapper.selectByPrimaryKey(blogId); } //condition 引數就是執行Cacheable的條件 @Cacheable(value = "common", key = "'blog_by_page'",condition = "#page == null") public List<Blog> getBlogByPage (Integer page, Integer size) { int start = 0; if (size == null) size = 10; if (page != null) { page = page <= 0 ? 1 : page; start = (page - 1) * size; } BlogExample example = new BlogExample(); example.setOrderByClause("blog_id desc limit "+ start + ","+ size); return blogMapper.selectByExampleWithBLOBs(example); } @Cacheable(value = "common", key = "'blog_all'") public List<Blog> getBlogs () { BlogExample example = new BlogExample(); example.setOrderByClause("blog_id desc"); return blogMapper.selectByExampleWithBLOBs(example); } //執行下面方法需要刪除三個快取的資料,所以使用Caching @Transactional @Caching(evict={@CacheEvict(value = "common", key="'blog_by_page'",condition="#blog!=null") , @CacheEvict(value = "common", key="'blog_all'",condition="#blog!=null") , @CacheEvict(value = "common", key="'blog_'+#blog.blogId",condition="#blog.blogId!=null")}) public int save (Blog blog) { if (blog == null) return 0; if (blog.getBlogId() == null) { return insert(blog); } return update(blog); } public int insert (Blog blog) { if (StringUtils.isBlank(blog.getAuthor()))blog.setAuthor("Cocoivan"); if (blog.getBlogType() == null)blog.setBlogType(EnumBlogType.MISCELLANEOUS.getValue()); return blogMapper.insertSelective(blog); } public int update (Blog blog) { return blogMapper.updateByPrimaryKeySelective(blog); } }
6.注意
Spring @Cacheable、@CacheEvict、@Caching是基於Spring AOP代理類,內部方法呼叫時,註解是失效的。
舉例子,Controller接收請求呼叫BlogService.save方法
快取相關注解不生效
@Transactional public int save (Blog blog) { if (blog == null) return 0; if (blog.getBlogId() == null) { return insert(blog); } return update(blog); } @Caching(evict={@CacheEvict(value = "common", key="'blog_by_page'",condition="#blog!=null") , @CacheEvict(value = "common", key="'blog_all'",condition="#blog!=null") , @CacheEvict(value = "common", key="'blog_'+#blog.blogId",condition="#blog.blogId!=null")}) public int insert (Blog blog) { if (StringUtils.isBlank(blog.getAuthor()))blog.setAuthor("Cocoivan"); if (blog.getBlogType() == null)blog.setBlogType(EnumBlogType.MISCELLANEOUS.getValue()); return blogMapper.insertSelective(blog); } @Caching(evict={@CacheEvict(value = "common", key="'blog_by_page'",condition="#blog!=null") , @CacheEvict(value = "common", key="'blog_all'",condition="#blog!=null") , @CacheEvict(value = "common", key="'blog_'+#blog.blogId",condition="#blog.blogId!=null")}) public int update (Blog blog) { return blogMapper.updateByPrimaryKeySelective(blog); }
快取相關注解生效
@Transactional @Caching(evict={@CacheEvict(value = "common", key="'blog_by_page'",condition="#blog!=null") , @CacheEvict(value = "common", key="'blog_all'",condition="#blog!=null") , @CacheEvict(value = "common", key="'blog_'+#blog.blogId",condition="#blog.blogId!=null")}) public int save (Blog blog) { if (blog == null) return 0; if (blog.getBlogId() == null) { return insert(blog); } return update(blog); } public int insert (Blog blog) { if (StringUtils.isBlank(blog.getAuthor()))blog.setAuthor("Cocoivan"); if (blog.getBlogType() == null)blog.setBlogType(EnumBlogType.MISCELLANEOUS.getValue()); return blogMapper.insertSelective(blog); } public int update (Blog blog) { return blogMapper.updateByPrimaryKeySelective(blog); }