1.12 缓存处理
1.12.1 缓存配置
SpringBoot2.0 的缓存可以使用注解方式实现。
- (1) 修改pom文件添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
- (2) 修改application-dev.properties配置文件
添加配置“spring.cache.type=redis” - (3) 添加@EnableCaching开启缓存注解
@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:可以标注在类上,抽取出相同的属性,简化代码。
@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 缓存使用
我们在服务层实现类中增加缓存注解
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操作只有第一次进入方法内部执行,后续的执行都直接返回缓存中的数据。