文章内容输入来源:拉勾教育Java高薪训练营
本文是Springboot课程学习中的一部分笔记。
本文详细介绍了Springboot自带的缓存使用、整合Redis实现注解式缓存与api式缓存,并配有详细的实现效果对比。
使用工具:idea2019.2
jdk版本:11
第一步,idea中新建项目,
导入依赖,
第二步,新建实体类Comment:
package com.lagou.pojo;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "t_comment")
public class Comment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String content;
private String author;
@Column(name = "a_id")
private Integer aId;
@Override
public String toString() {
return "Comment{" +
"id=" + id +
", content='" + content + '\'' +
", author='" + author + '\'' +
", aId=" + aId +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Integer getaId() {
return aId;
}
public void setaId(Integer aId) {
this.aId = aId;
}
}
第三步,使用Spring Data JPA来操作数据库:
package com.lagou.repository;
import com.lagou.pojo.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;
public interface CommentRepository extends JpaRepository<Comment,Integer> {
//根据评论id修改评论作者
@Transactional
@Modifying
@Query(value = "update t_comment c set c.author = ?1 where c.id=?2",nativeQuery = true)
public int updateComment(String author, Integer id);
}
第四步,创建Service:
package com.lagou.service;
import com.lagou.pojo.Comment;
import com.lagou.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
public Comment findCommentById(Integer id){
Optional<Comment> byId = commentRepository.findById(id);
if(byId.isPresent()){
Comment comment = byId.get();
return comment;
}
return null;
}
}
第六步,创建controller:
package com.lagou.controller;
import com.lagou.pojo.Comment;
import com.lagou.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CommentController {
@Autowired
private CommentService commentService;
@RequestMapping("/findCommentById")
public Comment findCommentById(Integer id){
Comment comment = commentService.findCommentById(id);
return comment;
}
}
测试:
可以看出每次执行都会查询sql,是因为没有开启缓存。
第一步,在启动类上添加注解,开启Springboot关于注解缓存的支持:
package com.lagou;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@EnableCaching
@SpringBootApplication
public class Springboot05CacheApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot05CacheApplication.class, args);
}
}
第二步,service上添加注解@Cacheable
package com.lagou.service;
import com.lagou.pojo.Comment;
import com.lagou.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
//@Cacheable: 将该方法查询结果comment存放在springboot默认缓存中//cacheNames: 起一个缓存命名空间 对应缓存唯一标识// value: 缓存结果 key:默认在只有一个参数的情况下,key值默认就是方法参数值 如果没有参数或者多个参数的情况:simpleKeyGenerate
@Cacheable(cacheNames = "comment")
public Comment findCommentById(Integer id){
Optional<Comment> byId = commentRepository.findById(id);
if(byId.isPresent()){
Comment comment = byId.get();
return comment;
}
return null;
}
}
第一步,添加依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
application.properties
#Redis服务连接配置
#Redis服务地址
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码
spring.redis.password=
在service中新增了两个方法,分别为更新和删除方法,并添加相应的缓存注解:
package com.lagou.service;
import com.lagou.pojo.Comment;
import com.lagou.repository.CommentRepository;
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.Optional;
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
//@Cacheable: 将该方法查询结果comment存放在springboot默认缓存中
//cacheNames: 起一个缓存命名空间 对应缓存唯一标识
// value: 缓存结果 key:默认在只有一个参数的情况下,key值默认就是方法参数值 如果没有参数或者多个参数的情况:simpleKeyGenerate
@Cacheable(cacheNames = "comment",unless = "#result==null")
public Comment findCommentById(Integer id){
Optional<Comment> byId = commentRepository.findById(id);
if(byId.isPresent()){
Comment comment = byId.get();
return comment;
}
return null;
}
//更新方法
@CachePut(cacheNames = "comment",key = "#result.id")
public Comment updateComment(Comment comment){
commentRepository.updateComment(comment.getAuthor(),comment.getId());
return comment;
}
//删除方法
@CacheEvict(cacheNames = "comment")
public void deleteComment(Integer id){
commentRepository.deleteById(id);
}
}
在controller中新增两个方法,对于service中更新和删除操作:
package com.lagou.controller;
import com.lagou.pojo.Comment;
import com.lagou.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CommentController {
@Autowired
private CommentService commentService;
@RequestMapping("/findCommentById")
public Comment findCommentById(Integer id){
Comment comment = commentService.findCommentById(id);
return comment;
}
@RequestMapping("/updateComment")
public Comment updateComment(Comment comment){
Comment commentById = commentService.findCommentById(comment.getId());
commentById.setAuthor(comment.getAuthor());
Comment comment1 = commentService.updateComment(commentById);
return comment1;
}
@RequestMapping("/deleteComment")
public void deleteComment(Integer id){
commentService.deleteComment(id);
}
}
对于缓存时间的全局设置:
application.properties:
# 对基于注解的Redis缓存数据统一设置有效期为1分钟,单位毫秒
spring.cache.redis.time-to-live=60000
新建一个service:
package com.lagou.service;
import com.lagou.pojo.Comment;
import com.lagou.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
@Service
public class ApiCommentService {
@Autowired
private CommentRepository commentRepository;
@Autowired
private RedisTemplate redisTemplate;
// 使用API方式进行缓存:先去缓存中查找,缓存中有,直接返回,没有,查询数据库
public Comment findCommentById(Integer id){
Object o = redisTemplate.opsForValue().get("comment_" + id);
if(o!=null){
//查询到了数据,直接返回
return (Comment) o;
}else {
//缓存中没有,从数据库查询
Optional<Comment> byId = commentRepository.findById(id);
if(byId.isPresent()){
Comment comment = byId.get();
//将查询结果存到缓存中,同时还可以设置有效期为1天
redisTemplate.opsForValue().set("comment_" + id,comment,1, TimeUnit.DAYS);
return comment;
}
}
return null;
}
//更新方法
public Comment updateComment(Comment comment){
commentRepository.updateComment(comment.getAuthor(),comment.getId());
//将更新数据进行缓存更新
redisTemplate.opsForValue().set("comment_" + comment.getId(),comment);
return comment;
}
//删除方法
public void deleteComment(Integer id){
commentRepository.deleteById(id);
redisTemplate.delete("comment_" + id);
}
}
controller基本没变:
package com.lagou.controller;
import com.lagou.pojo.Comment;
import com.lagou.service.ApiCommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("api")
public class ApiCommentController {
@Autowired
private ApiCommentService commentService;
@RequestMapping("/findCommentById")
public Comment findCommentById(Integer id){
Comment comment = commentService.findCommentById(id);
return comment;
}
@RequestMapping("/updateComment")
public Comment updateComment(Comment comment){
Comment commentById = commentService.findCommentById(comment.getId());
commentById.setAuthor(comment.getAuthor());
Comment comment1 = commentService.updateComment(commentById);
return comment1;
}
@RequestMapping("/deleteComment")
public void deleteComment(Integer id){
commentService.deleteComment(id);
}
}
效果:
定义一个Config类:
package com.lagou.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
@Configuration
public class RedisConfig {
// 自定义一个RedisTemplate
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 创建JSON格式序列化对象,对缓存数据的key和value进行转换
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// 解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//设置redisTemplate模板API的序列化方式为json
template.setDefaultSerializer(jackson2JsonRedisSerializer);
return template;
}
}
但要注意,我们这种方式只是针对于api实现redis缓存的处理方式,而对于基于注解的redis缓存是没有作用的。
下面我们继续来实现基于注解的redis缓存的序列化实现:
在之前的RedisConfig.java中添加如下配置:
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换
RedisSerializer<String> strSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jacksonSeial =
new Jackson2JsonRedisSerializer(Object.class);
// 解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 定制缓存数据序列化方式及时效
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(strSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(jacksonSeial))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager
.builder(redisConnectionFactory).cacheDefaults(config).build();
return cacheManager;
}
平时工作中大多是从事于crud之类的体力活,渐渐的自己也会感觉失去了前进的方向,迷茫了。自己反思了一段时间,还是自己在技术的系统性架构层面非常欠缺,没有进行过系统性的学习,说来也是缘分,正是我迷茫的那段时间,拉勾教育的Java高薪训练营课程走到了我的面前,看了下大纲之后,感觉课程内容特别丰富,有许多我的短板,于是我就果断报名了,学了一段时间,感觉超值,各位大佬老师讲的特别好,还配有每周的直播答疑,服务很好,班级里同学学习氛围也很浓厚,真庆幸自己报了名,遇见这么多优秀的人。自己给自己立个flag,一定要坚持学完,在技术上面更进一步,这就是2020年后半年的奋斗目标了。