准备数据
使用“Spring Boot数据访问,整合MyBatis,JPA,Redis”文章使用到的数据库springbootdata
创建项目
创建Spring Boot项目引入JPA、MySQL、Web依赖
编写数据库表对应的实体类
新建domain包,在该包下编写数据库表t_comment对应的实体类Comment,并使用JPA相关注解配置映射关系
import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "t_comment")
public class Comment{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String content;
private String author;
@Column(name = "a_id") //指定映射的表字段名
private Integer 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;
}
@Override
public String toString() {
return "Comment{" +
"id=" + id +
", content='" + content + '\'' +
", author='" + author + '\'' +
", aId=" + aId +
'}';
}
}
编写数据库操作的Repository接口文件
新建repository包,在该包下创建一个用于操作Comment实体的Repository接口,该接口继承JpaRepository
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;
import zzd.example.chapter06.domain.Comment;
public interface CommentRespository extends JpaRepository<Comment,Integer> {
//根据评论id修改评论作者author
@Transactional
@Modifying
@Query("UPDATE t_comment c SET c.author = ?1 WHERE c.id = ?2")
public int updateComment(String author,Integer id);
}
编写业务操作类Service文件
新建service包,在该包下创建一个用于Comment相关业务模块操作的Service实体类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import zzd.example.chapter06.domain.Comment;
import zzd.example.chapter06.repository.CommentRespository;
import java.util.Optional;
@Service
public class CommentService {
@Autowired
private CommentRespository commentRespository;
//根据评论id查询评论信息
public Comment findById(int comment_id){
Optional<Comment> optional = commentRespository.findById(comment_id);
if (optional.isPresent()){
return optional.get();
}
return null;
}
public Comment updateComment(Comment comment){
commentRespository.updateComment(comment.getAuthor(),comment.getaId());
return comment;
}
public void deleteComment(int comment_id){
commentRespository.deleteById(comment_id);
}
}
编写Web访问层Controller文件
新建controller包,在该包下创建一个用于Comment访问控制的Controller实体类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import zzd.example.chapter06.domain.Comment;
import zzd.example.chapter06.service.CommentService;
@RestController
public class CommentController {
@Autowired
private CommentService commentService;
@GetMapping("/get/{id}")
public Comment findById(@PathVariable("id") int comment_id){
Comment comment = commentService.findById(comment_id);
return comment;
}
@GetMapping("/update/{id}/{author}")
public Comment upfdateComment(@PathVariable("id") int comment_id,@PathVariable("author") String author){
Comment comment = commentService.findById(comment_id);
comment.setAuthor(author);
Comment updateComment = commentService.updateComment(comment);
return updateComment;
}
@GetMapping("/delete/{id}")
public void deleCopmment(@PathVariable("id") int comment_id){
commentService.deleteComment(comment_id);
}
}
编写全局配置文件
#MySQL数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
#显示使用JPA进行数据库查询的SQL语句
spring.jpa.show-sql=true
基于注解的Redis缓存实现
添加Spring Data Redis依赖启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Redis服务连接配制,在全局文件中添加Redis服务的连接配置
#Redis服务器地址
spring.redis.host=192.168.110.110
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
#spring.redis.password=
#对基于注解的Redis缓存数据同意设置有效期为1分钟,单位毫秒
spring.cache.redis.time-to-live=60000
对CommentService类中的方法进行修改,使用@Cacheable、@CachePut、@CacheEvict3个注解制定缓存管理
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import zzd.example.chapter06.domain.Comment;
import zzd.example.chapter06.repository.CommentRespository;
import java.util.Optional;
@Service
public class CommentService {
@Autowired
private CommentRespository commentRespository;
//根据评论id查询评论信息
//查询缓存
@Cacheable(cacheNames = "comment",unless = "#result==null")
public Comment findById(int comment_id){
Optional<Comment> optional = commentRespository.findById(comment_id);
if (optional.isPresent()){
return optional.get();
}
return null;
}
//更新缓存
@Cacheable(cacheNames = "comment",key="#result.id")
public Comment updateComment(Comment comment){
commentRespository.updateComment(comment.getAuthor(),comment.getaId());
return comment;
}
//删除缓存
@CacheEvict(cacheNames = "comment")
public void deleteComment(int comment_id){
commentRespository.deleteById(comment_id);
}
}
将缓存对象实现序列化、实体类实现JDK自带序列化接口Serializable
import javax.persistence.*;
import java.io.Serializable;
@Entity(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;
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;
}
@Override
public String toString() {
return "Comment{" +
"id=" + id +
", content='" + content + '\'' +
", author='" + author + '\'' +
", aId=" + aId +
'}';
}
}
效果测试
项目启动成功,通过浏览器访问:http://licalhost:8080/get/1 不管刷新多少次控制都只打印一次
在配置类中统一配置Redis数据的有效期,这种方式相对来说不过灵活,并且这种设置对基于API的Redis换成实现没有效果
基于API的Redis缓存实现
使用RedisAPI进行业务数据缓存管理
在service包下编写一个业务处理类ApiCommentService
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import zzd.example.chapter06.domain.Comment;
import zzd.example.chapter06.repository.CommentRespository;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
@Service
public class ApiCommentService {
@Autowired
private CommentRespository commentRespository;
@Autowired
private RedisTemplate redisTemplate;
public Comment findById(int comment_id){
//先从Redis缓存中查询数据
Object object = redisTemplate.opsForValue().get("comment_"+comment_id);
if (object!=null){
return (Comment)object;
}else {
//缓存中没有,就是进入数据库查询
Optional<Comment> optional = commentRespository.findById(comment_id);
if (optional.isPresent()){
Comment comment = optional.get();
//将查询结果进行,并设置有效期为1天
redisTemplate.opsForValue().set("comment_"+comment_id,comment,1, TimeUnit.DAYS);
return comment;
}else {
return null;
}
}
}
public Comment updateComment(Comment comment){
commentRespository.updateComment(comment.getAuthor(),comment.getaId());
//更新数据后进行缓存更新
redisTemplate.opsForValue().set("comment_"+comment.getId(),comment);
return comment;
}
public void deleteComment(int comment_id){
commentRespository.deleteById(comment_id);
//删除数据后进行患处删除
redisTemplate.delete("comment_"+comment_id);
}
}
编写Web访问层Controller文件
在controller包下创建Controller实体类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import zzd.example.chapter06.domain.Comment;
import zzd.example.chapter06.service.ApiCommentService;
@RestController
@RequestMapping("/api")
public class ApiCommentController {
@Autowired
private ApiCommentService apiCommentService;
@GetMapping("/get/{id}")
public Comment findById(@PathVariable("id") int comment_id){
Comment comment = apiCommentService.findById(comment_id);
return comment;
}
@GetMapping("/update/{id}/{author}")
public Comment updateComment(@PathVariable("id")int comment_id,@PathVariable("author")String author){
Comment comment = apiCommentService.findById(comment_id);
comment.setAuthor(author);
Comment updateComment = apiCommentService.updateComment(comment);
return updateComment;
}
@GetMapping("/delete/{id}")
public void deleComment(@PathVariable("id")int comment_id){
apiCommentService.deleteComment(comment_id);
}
}
自定义Redis缓存序列化机制
自定义JSON格式的数据序列化机制进行数据缓存管理
RedisAPI默认序列化机制
自定义Redis Template序列化机制
在config包下自定义配置类RedisConfig
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.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration //自定义一个序列化配置类 实现JSON格式缓存数据
public class RedisConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//使用json格式序列化对象,对缓存数据key和value进行转换
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);
//设置RedisTemplate模板API的序列化方式为Json
template.setDefaultSerializer(jacksonSeial);
return template;
}
}
Redis注解默认序列化机制
自定义RedisCacheManager
在config包下自定义配置类RedisConfig
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.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration //敌意一个序列化配置类 实现JSON格式缓存数据
public class RedisConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//使用json格式序列化对象,对缓存数据key和value进行转换
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);
//设置RedisTemplate模板API的序列化方式为Json
template.setDefaultSerializer(jacksonSeial);
return template;
}
//基于注解的redis缓存实现也使用自定义的序列化机制
@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)) //key的值为string
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial)) //value的值为json
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
return cacheManager;
}
}