前言
本项目主要采用H2作为数据库,Durid作为连接池,JPA作为持久层框架,Redis作为缓存。
注:本章与之前的使用H2Database+Druid连接池+Spring Data JPA+Ehcache实现CRUD操作,大同小异,所不同的是这里使用的是Redis缓存。如果相关概念不清楚,请查看上篇。
一、导入依赖包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.scb</groupId>
<artifactId>springboot-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.11</version>
</dependency>
<!-- Using JSP -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>8.5.31</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<!-- Using Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- 不依赖Redis的异步客户端lettuce -->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 阿里系的Druid依赖包 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<!-- Druid 依赖 log4j包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二、配置缓存管理器
Spring在使用缓存注解前,需要配置缓存管理器,缓存管理器将提供一些重要的信息,如缓存类型、超时时间等。
在SpringBoot中配置缓存管理器很简单,只需要在application.yml中配置相关细节,SpringBoot就会自动装配他。
spring:
#使用jsp视图
mvc:
view:
prefix: /WEB-INF/jsp/
suffix: .jsp
#配置Redis的缓存管理器
cache:
cache-names: redisCache
type: redis
#redis配置
redis:
port: 6379
host: localhost
jedis:
pool:
min-idle: 5
max-active: 10
max-idle: 10
#配置JPA
jpa:
generate-ddl: false
show-sql: true #print DB sql
hibernate:
ddl-auto: update
#配置h2数据库
h2:
console:
path: /h2-console
enabled: true
settings:
web-allow-others: true
datasource:
platform: h2
url: jdbc:h2:~/user
username: sa
password:
name: test
#使用druid连接池
type: com.alibaba.druid.pool.DruidDataSource
druid:
min-idle: 2
initial-size: 5
max-active: 10
max-wait: 5000
validation-query: select 1
server:
port: 8090
然后我们还需要在Application主类(SpringBoot的运行类)中加上@EnableCaching
package com.scb.springbootdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching //启动缓存机制
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
这样,使用Redis作为缓存就配置好了。
三、实体层开发
package com.scb.springbootdemo.entity;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
@Data
@Entity(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = 5150128533924554727L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "userName",nullable = false)
private String userName;
@Column(name = "note",nullable = false)
private String note;
}
四、dao层
package com.scb.springbootdemo.repository;
import com.scb.springbootdemo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<User,Long> {
List<User> findByUserNameAndNote(String username, String note);
}
五、service层
package com.scb.springbootdemo.service;
import com.scb.springbootdemo.entity.User;
import java.util.List;
public interface IUserService {
User getUser(Long id);
List<User> getAllUsers();
User insertUser(User user);
User updateUserName(Long id,String userName);
List<User> findUsers(String userName,String note);
void deleteUser(Long id);
}
package com.scb.springbootdemo.service;
import com.scb.springbootdemo.entity.User;
import com.scb.springbootdemo.repository.UserRepository;
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 org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class UserServiceImpl implements IUserService {
@Autowired
UserRepository userRepository;
@Override
@Cacheable(value = "redisCache",key = "'redis_user_'+#id")
public User getUser(Long id) {
return userRepository.getOne(id);
}
@Override
public List<User> getAllUsers() {
return userRepository.findAll();
}
@Override
@CachePut(value = "redisCache",key = "'redis_user_'+#result.id")
public User insertUser(User user) {
return userRepository.save(user);
}
@Override
@CachePut(value = "redisCache",condition = "#result != 'null'",key = "'redis_user_'+#id")
public User updateUserName(Long id, String userName) {
User user=this.getUser(id);
if(user == null){
return null;
}
user.setUserName(userName);
return userRepository.save(user);
}
@Override
public List<User> findUsers(String userName, String note) {
return userRepository.findByUserNameAndNote(userName,note);
}
@Override
@CacheEvict(value = "redisCache",key = "'redis_user_'+#id",beforeInvocation = false)
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
六、controller层
package com.scb.springbootdemo.controller;
import com.scb.springbootdemo.entity.User;
import com.scb.springbootdemo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(path = "/user",produces="application/json;charset=utf-8")
public class RedisCachingController {
@Autowired
IUserService userService;
@GetMapping("/{id}")
public User getUser(@PathVariable Long id){
return userService.getUser(id);
}
@GetMapping
public List<User> getAllUsers(){
return userService.getAllUsers();
}
@GetMapping("/{userName}/{note}")
public List<User> findUsers(@PathVariable String userName,@PathVariable String note){
return userService.findUsers(userName,note);
}
@PostMapping("/{userName}/{note}")
public User insertUser(@PathVariable String userName,@PathVariable String note){
User user=new User();
user.setUserName(userName);
user.setNote(note);
return userService.insertUser(user);
}
@PutMapping("/{id}/{userName}")
public User updateUserName(@PathVariable Long id,@PathVariable String userName){
return userService.updateUserName(id,userName);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id){
userService.deleteUser(id);
}
}
七、测试
上面项目已经开发完毕,下面我们运行项目,并使用postman进行测试。
以post请求访问http://localhost:8090/user/zhang/san,是新建一个user对象。然后我们在Redis客户端查看是否存入:
可以看到,缓存已经存入。
通过查看该key的超时时间,可以发现是-1,这代表该缓存永不过期。这是很糟糕的,我们一般对于缓存都需要设置一个超时时间,具体配置如下:
八、自定义Redis缓存管理器
在上面RedisConfig配置类中,加入以下配置信息。
//自定义Redis缓存管理器
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){
//Redis加锁的写入器
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(redisConnectionFactory);
//启动Redis缓存的默认设置
RedisCacheConfiguration cacheConfiguration=RedisCacheConfiguration.defaultCacheConfig();
//设置JDK序列化器
cacheConfiguration=cacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()));
//禁用前缀
cacheConfiguration=cacheConfiguration.disableKeyPrefix();
//设置10min超时时间
cacheConfiguration=cacheConfiguration.entryTtl(Duration.ofMinutes(10));
//创建Redis缓存管理器
RedisCacheManager redisCacheManager=new RedisCacheManager(writer,cacheConfiguration);
return redisCacheManager;
}
此时,在以post请求访问http://localhost:8090/user/zhang/san,新建一个user对象。然后我们在Redis客户端查看:
可以看到新创建的key不仅去掉了"redisCache"前缀,而且设置了一个10分钟的超时时间。
当超过10分钟时,超时时间显示为-2,这表示已经过期。此时,在取key的值时,将会为空(nil)