原始template开发会入侵业务代码,与业务代码耦合。不容易阅读对管理业务代码造成了麻烦,并且会对事务产生影响。redis端抛出的异常会影响到数据库端的事务,使正常的业务数据一起回滚。为此spring提供了一套基于注解的缓存开发方案,解决了上述问题。
1.完善对spring对aop的依赖
spring的@cache注解是基于于aop实现。实际使用过程中,因为aop依赖不完整,会出现很多的异常情况。
我遇到过抛出:no cache could be resolved for builder异常,@cachePut注解变成删除,@CacheEvict失效。因为完善spring对aop依赖至关重要。除了加入spring原生的aop组件外,还要加入以下依赖。
<!-- aop 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
并且要在spring配置文件中添加以下字段,将jdk代理改为cglib代理。
<aop:aspectj-autoproxy proxy-target-class="true">
2.在spring配置文件contex.txml导入对cache组件的支持
<!-- 开启缓存注解驱动 -->
<cache:annotation-driven/>
<!-- 声明redis缓存的管理器 -->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg index="0" ref="redisTemplate"/>
</bean>
3.在业务层添加cache注解
@Service
public class UserServiceImpl2 implements UserService {
public static Logger logger = Logger.getLogger(UserServiceImpl2.class);
@Autowired
private UserMapper userMpper;//usermapper接口
@Transactional
@CachePut(key="#user.id",value="userCache")
public User addUser(User user) {
userMpper.insert(user);
logger.info("向数据库添加用户");
return user;
}
@Transactional
@CacheEvict(key="#userId",value="user")
public void deleteUser(String userId) {
userMpper.deleteByPrimaryKey(userId);
}
@Transactional
@CachePut(key="#user.id",value="user")
public User updateUser(User user) {
userMpper.updateByPrimaryKeySelective(user);
return user;
}
@Transactional(readOnly=true)
@Cacheable(key="#userId",value="user")
public User queryUser(String userId) {
logger.info("从数据库里取得用户");
User user = userMpper.selectByPrimaryKey(userId);
return user;
}
}
注释介绍
@CachePut
@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,方法调用成功后就会将参数缓存到redis中。
@CachePut 作用和配置方法
参数解释
value 缓存的名称,必须指定至少一个 @CachePut(value=”my cache”)
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 @CachePut(value=”testcache”,key=”#userName”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 @CachePut(value=”testcache”,condition=”#userName.length()>2”)
@CachePut 注释,这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新。
- 实例
@Test
public void testAddUser() {
User user = new User();
user.setId("001");
user.setUsername("username");
user.setPassword("password");
service.addUser(user);
}
@Transactional
@CachePut(key="#user.id",value="userCache")
public User addUser(User user) {
userMpper.insert(user);
logger.info("向数据库添加用户");
return user;
}
缓存成功后redis生成的数据
@Cacheable 作用和配置方法
@Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@Cacheable 主要的参数
value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:
@Cacheable(value=”mycache”) 或者
@Cacheable(value={”cache1”,”cache2”}
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如:
@Cacheable(value=”userCahe”,key=”#userName”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如:
@Cacheable(value=”userCahe”,condition=”#userName.length()>0)
@Cacheable(key=”#user.id” value=”userCahe”),这个注释的意思是,当调用这个方法的时候,会查询传入对象的id,如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中,否则返回缓存中的对象。
- 实例
@Transactional(readOnly=true)
@Cacheable(key="#userId",value="user")
public User queryUser(String userId) {
logger.info("从数据库里取得用户");
User user = userMpper.selectByPrimaryKey(userId);
return user;
}
@CacheEvict
@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空
@CacheEvict 作用和配置方法
参数解释
value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 @CacheEvict(value=”my cache”)
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 @CacheEvict(value=”testcache”,key=”#userName”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 @CacheEvict(value=”testcache”,condition=”#userName.length()>2”)
allEntries 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 @CachEvict(value=”testcache”,allEntries=true)
beforeInvocation 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 @CachEvict(value=”testcache”,beforeInvocation=true)
- 实例
@Transactional
@CacheEvict(key="#userId",value="user")
public void deleteUser(String userId) {
userMpper.deleteByPrimaryKey(userId);
}