1.12 缓存处理

1.12.1 缓存配置

SpringBoot2.0 的缓存可以使用注解方式实现。

  • (1) 修改pom文件添加依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
  • (2) 修改application-dev.properties配置文件
    添加配置“spring.cache.type=redis”

  • (3) 添加@EnableCaching开启缓存注解

1
2
3
4
5
6
7
8
9
10
11

@EnableCaching
@ServletComponentScan
@SpringBootApplication(scanBasePackages = {"com.zone7.demo.helloworld"})
public class HelloworldApplication {

public static void main(String[] args) {
SpringApplication.run(HelloworldApplication.class, args);
}

}

1.12.2 注解说明

在需要使用缓存的方法上面添加以下注解:
- @Cacheable 将方法的运行结果进行缓存;第二次再要相同的数据,直接从缓存中获取,不再调用方法;
- @CacheEvict 移除缓存
- @CachePut 修改了数据库的某个数据,同时更新缓存

以下对这三个注解的属性展开介绍:

  • (1) @Cacheable
    Cacheable中的几个属性:
    • 1)cacheNames/value:指定缓存组件的名字, 数组的方式,可以指定多个缓存组件名称。
    • 2)key: 缓存数据使用的key,默认使用方法参数的值作为key。也可以自己指定,通过编写SpEL指定key的值;如:#root.methodName 、#id等。
    • 3)keyGenerator: key的生成器,可以自己编写key的生成器组件。注意:在使用时key和keyGenerator二选一。
    • 4)cacheManager: 指定缓存管理器。
    • 5)condition: 指定符合条件的情况下才缓存;如: condition = “#id>0” “#a0>1”才进行缓存。
    • 6)unless: 否定缓存; 当unless指定的条件为true,方法的返回值就不会缓存;如:可以获取到结果进行判断unless = “#result == null “ 当方法结果为null时,不缓存。
    • 7)sync: 是否使用异步模式
  • (2) @CacheEvit
    • @CacheEvit:缓存清除
    • @CacheEvit和@Cacheable的相同属性就不再赘述。
      • 1)allEntries = true 每次删除,将指定缓存中的所有数据全都删除。
      • 2)beforeInvocation=false ,缓存的清除是否是在方法之前执行,默认false, 即在方法之后清除,当方法执行出现异常时,缓存不会清除。
      • 3)beforeInvocation=true ,方法之前清除,无论方法执行是否出现异常,缓存都会清除。
  • (3) @CachePut
    运行时机:先调用目标方法,将目标方法的结果缓存起来,属性与@Cacheable相同。
    此外还有@CacheConfig:可以标注在类上,抽取出相同的属性,简化代码。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CacheConfig {
    String[] cacheNames() default {};
    String keyGenerator() default "";
    String cacheManager() default "";
    String cacheResolver() default "";
    }

1.12.3 缓存使用

我们在服务层实现类中增加缓存注解

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package com.zone7.demo.helloworld.sys.service.impl;

import com.zone7.demo.helloworld.commons.exception.AddOPException;
import com.zone7.demo.helloworld.commons.exception.DeleteOPException;
import com.zone7.demo.helloworld.commons.exception.UpdateOPException;
import com.zone7.demo.helloworld.sys.dao.SysUserMapper;
import com.zone7.demo.helloworld.sys.pojo.SysUser;
import com.zone7.demo.helloworld.sys.service.SysUserService;
import com.zone7.demo.helloworld.sys.vo.SysUserVo;
import com.zone7.demo.helloworld.utils.MD5Util;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
* SysUserServiceImpl
*
* @author: zone7
* @time: 2019.02.17
*/
@Service
@CacheConfig(cacheNames = "users")
public class SysUserServiceImpl implements SysUserService {

@Value("${system.default.password}")
private String defaultPassword;

@Autowired
private SysUserMapper sysUserMapper;

@Autowired
private StringRedisTemplate stringRedisTemplate;



@Override
@Transactional(rollbackFor = AddOPException.class)
@CachePut
public SysUserVo save(SysUserVo userVo) {
try {


String password = defaultPassword;
String md5Password = MD5Util.encode(password);
SysUser sysUser = SysUser.builder()
.name(userVo.getName()).password(md5Password)
.phone(userVo.getPhone())
.department(userVo.getDepartment())
.build();


// 存储用户信息
sysUserMapper.insertSelective(sysUser);

SysUserVo vo=new SysUserVo();
BeanUtils.copyProperties(sysUser,vo);

return vo;

} catch (Exception e) {

throw new AddOPException("新增用户操作出错,错误原因: " + e.getMessage());
}
}

@Override
@Transactional(rollbackFor = UpdateOPException.class)
@CachePut
public void update(SysUserVo userVo) {
try {

SysUser after = SysUser.builder()
.id(userVo.getId())
.name(userVo.getName())
.phone(userVo.getPhone())
.department(userVo.getDepartment()).build();

sysUserMapper.updateByPrimaryKeySelective(after);

} catch (Exception e) {

throw new UpdateOPException("更新用户操作出错,错误原因: " + e.getMessage());
}
}

@Override
@Cacheable
public SysUserVo findById(Integer id) {
SysUser user = sysUserMapper.selectByPrimaryKey(id);
SysUserVo vo=new SysUserVo();
BeanUtils.copyProperties(user,vo);
return vo;
}


@Override
public List<SysUserVo> findByName( String name) {
List<SysUser> users = sysUserMapper.findByName(name);

List<SysUserVo> userList = new ArrayList<SysUserVo>();
users.forEach(sysUser -> {
// 查询角色信息
SysUserVo vo=new SysUserVo();
BeanUtils.copyProperties(sysUser,vo);
userList.add(vo);
});
return userList;
}

@Override
@Transactional(rollbackFor = DeleteOPException.class)
@CacheEvict
public void delete(Integer id) {
try {
sysUserMapper.deleteByPrimaryKey(id);

} catch (Exception e) {
e.printStackTrace();
throw new DeleteOPException("删除用户操作出错,错误原因: " + e.getMessage());
}
}

}

通过Postman测试执行两次findById操作只有第一次进入方法内部执行,后续的执行都直接返回缓存中的数据。

测试缓存