spring-redis缓存方案学习二:基于spring的@cache注解开发

来源:互联网 发布:极度深寒游戏知乎 编辑:程序博客网 时间:2024/06/05 11:40

原始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注解

@Servicepublic 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生成的数据
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);    }