Springboot 项目运用 Redis 缓存数据

介绍

Springboot 项目与 Redis 结合获取数据

pom 依赖

主要是 mybatis、redis 的相关依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
server:
servlet:
context-path: /web
port: 8080

spring:
datasource:
druid:
# 数据库访问配置, 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?useunicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: 123456
# 连接池配置
initial-size: 5
min-idle: 5
max-active: 20
# 连接等待超时时间
max-wait: 30000
# 配置检测可以关闭的空闲连接间隔时间
time-between-eviction-runs-millis: 60000
# 配置连接在池中的最小生存时间
min-evictable-idle-time-millis: 300000
validation-query: select '1' from dual
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
max-open-prepared-statements: 20
max-pool-prepared-statement-per-connection-size: 20
# 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙
filters: stat,wall
# Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔
aop-patterns: com.springboot.servie.*

redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: localhost
# Redis服务器连接端口
port: 6379

logging:
level:
com.example.demo.dao: debug

Redis 配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

// 自定义缓存key生成策略
@Override
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}

// 缓存管理器
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager cacheManager = RedisCacheManager.create(connectionFactory);
return cacheManager;
}

@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
setSerializer(template);// 设置序列化工具
template.afterPropertiesSet();
return template;
}

private void setSerializer(StringRedisTemplate template) {
@SuppressWarnings({ "rawtypes", "unchecked" })
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);
template.setValueSerializer(jackson2JsonRedisSerializer);
}
}

dao 层以及实现

使用 MyBatis 注解方式实现数据访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Mapper
public interface StudentManager {

@Update("update student set sname=#{sname},ssex=#{ssex} where sno=#{sno}")
int update(Student student);

@Delete("delete from student where sno=#{sno}")
void deleteStudentBySno(String sno);

@Select("select * from student where sno=#{sno}")
@Results(id = "student", value = { @Result(property = "sno", column = "sno", javaType = String.class),
@Result(property = "sname", column = "sname", javaType = String.class),
@Result(property = "ssex", column = "ssex", javaType = String.class) })
Student queryStudentBySno(String sno);
}

service 层及实现

queryStudentBySno 方法使用了注解 @Cacheable(key=”#p0”),即将 id 作为 redis 中的 key 值

  • @CacheConfig(cacheNames = “student”) 一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的
  • @Cacheable 是用来声明方法是可缓存的
  • @CachePut 主要用于数据新增和修改操作上
  • @CacheEvict 通常用在删除方法上,用来从缓存中移除相应数据
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    @CacheConfig(cacheNames = "student")
    public interface StudentService {

    @CachePut(key = "#p0.sno")
    Student update(Student student);

    @CacheEvict(key = "#p0", allEntries = true)
    void deleteStudentBySno(String sno);

    @Cacheable(key = "#p0")
    Student queryStudentBySno(String sno);

    }

    @Service
    public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentManager studentManager;

    @Override
    public Student update(Student student) {
    this.studentManager.update(student);
    return this.studentManager.queryStudentBySno(student.getSno());
    }

    @Override
    public void deleteStudentBySno(String sno) {
    this.studentManager.deleteStudentBySno(sno);
    }

    @Override
    public Student queryStudentBySno(String sno) {
    return this.studentManager.queryStudentBySno(sno);
    }
    }

Test 用例

第一次从数据库中读取,第二次直接从缓存读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

@Autowired
private StudentService studentService;

@Test
public void contextLoads() {
System.out.println(studentService.queryStudentBySno("001").toString());
System.out.println(studentService.queryStudentBySno("001").toString());
}

}


2019-08-10 17:27:32.739 DEBUG 7140 --- [ main] c.e.d.d.S.queryStudentBySno : ==> Preparing: select * from student where sno=?
2019-08-10 17:27:33.053 DEBUG 7140 --- [ main] c.e.d.d.S.queryStudentBySno : ==> Parameters: 001(String)
2019-08-10 17:27:33.108 DEBUG 7140 --- [ main] c.e.d.d.S.queryStudentBySno : <== Total: 1
Student(sno=001, sname=KangKang, ssex=M )
Student(sno=001, sname=KangKang, ssex=M )

总结