Spring思维导图,让Spring不再难懂(cache篇)

关于缓存

缓存是实际工作中非常常用的一种提高性能的方法。而在java中,所谓缓存,就是将程序或系统经常要调用的对象存在内存中,再次调用时可以快速从内存中获取对象,不必再去创建新的重复的实例。这样做可以减少系统开销,提高系统效率。

在增删改查中,数据库查询占据了数据库操作的80%以上,而非常频繁的磁盘I/O读取操作,会导致数据库性能极度低下。而数据库的重要性就不言而喻了:

  • 数据库通常是企业应用系统最核心的部分

  • 数据库保存的数据量通常非常庞大

  • 数据库查询操作通常很频繁,有时还很复杂


在系统架构的不同层级之间,为了加快访问速度,都可以存在缓存


缓存不同层级的作用.png



spring cache特性与缺憾


现在市场上主流的缓存框架有ehcache、redis、memcached。spring cache可以通过简单的配置就可以搭配使用起来。其中使用注解方式是最简单的。


特性与缺憾.png



Cache注解



缓存注解.png


从以上的注解中可以看出,虽然使用注解的确方便,但是缺少灵活的缓存策略,

缓存策略:

  • TTL(Time To Live )
    存活期,即从缓存中创建时间点开始直到它到期的一个时间段(不管在这个时间段内有没有访问都将过期)

  • TTI(Time To Idle)
    空闲期,即一个数据多久没被访问将从缓存中移除的时间

项目中可能有很多缓存的TTL不相同,这时候就需要编码式使用编写缓存。


条件缓存


根据运行流程,如下@Cacheable将在执行方法之前( #result还拿不到返回值)判断condition,如果返回true,则查缓存;


@Cacheable(value = "user", key = "#id", condition = "#id lt 10")  
public User conditionFindById(final Long id)



如下@CachePut将在执行完方法后(#result就能拿到返回值了)判断condition,如果返回true,则放入缓存


@CachePut(value = "user", key = "#id", condition = "#result.username ne 'zhang'")  
public User conditionSave(final User user)



如下@CachePut将在执行完方法后(#result就能拿到返回值了)判断unless,如果返回false,则放入缓存;(即跟condition相反)


@CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'")  
public User conditionSave2(final User user)


如下@CacheEvict, beforeInvocation=false表示在方法执行之后调用(#result能拿到返回值了);且判断condition,如果返回true,则移除缓存;


@CacheEvict(value = "user", key = "#user.id", beforeInvocation = false, condition = "#result.username ne 'zhang'"
public User conditionDelete(final User user)


  • 小试牛刀,综合运用:


    @CachePut(value = "user", key = "#user.id")
       public User save(User user{
           users.add(user);
           return user;
       }

       @CachePut(value = "user", key = "#user.id")
       public User update(User user{
           users.remove(user);
           users.add(user);
           return user;
       }

       @CacheEvict(value = "user", key = "#user.id")
       public User delete(User user{
           users.remove(user);
           return user;
       }

       @CacheEvict(value = "user", allEntries = true)
       public void deleteAll({
           users.clear();
       }

       @Cacheable(value = "user", key = "#id")
       public User findById(final Long id{
           System.out.println("cache miss, invoke find by id, id:" + id);
           for (User user : users) {
               if (user.getId().equals(id)) {
                   return user;
               }
           }
           return null;
       }





配置ehcache与redis


  • spring cache集成ehcache,spring-ehcache.xml主要内容:



<dependency>
   <groupId>net.sf.ehcache</groupId>
   <artifactId>ehcache-core</artifactId>
   <version>${ehcache.version}</version>
</dependency>




<!-- Spring提供的基于的Ehcache实现的缓存管理器 -->
   
<!-- 如果有多个ehcacheManager要在bean加上p:shared="true" -->
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation" value="classpath:xml/ehcache.xml"/>
</bean>
   
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="ehcacheManager"/>
    <property name="transactionAware" value="true"/>
</bean>
   
<!-- cache注解,和spring-redis.xml中的只能使用一个 -->
<cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>



  • spring cache集成redis,spring-redis.xml主要内容:



<dependency>
   <groupId>org.springframework.data</groupId>
   <artifactId>spring-data-redis</artifactId>
   <version>1.8.1.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-pool2</artifactId>
   <version>2.4.2</version>
</dependency>
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.9.0</version>
</dependency>




<!-- 注意需要添加Spring Data Redis等jar包 -->
<description>redis配置</description>

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
   <property name="maxIdle" value="${redis.pool.maxIdle}"/>
   <property name="maxTotal" value="${redis.pool.maxActive}"/>
   <property name="maxWaitMillis" value="${redis.pool.maxWait}"/>
   <property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>
   <property name="testOnReturn" value="${redis.pool.testOnReturn}"/>
</bean>

<!-- JedisConnectionFactory -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
   <property name="hostName" value="${redis.master.ip}"/>
   <property name="port" value="${redis.master.port}"/>
   <property name="poolConfig" ref="jedisPoolConfig"/>
</bean>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
     p:connectionFactory-ref="jedisConnectionFactory">

   <property name="keySerializer">
       <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
   </property>
   <property name="valueSerializer">
       <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
   </property>
   <property name="hashKeySerializer">
       <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
   </property>
   <property name="hashValueSerializer">
       <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
   </property>
</bean>

<!--spring cache-->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
     c:redisOperations-ref="redisTemplate">

   <!-- 默认缓存10分钟 -->
   <property name="defaultExpiration" value="600"/>
   <property name="usePrefix" value="true"/>
   <!-- cacheName 缓存超时配置,半小时,一小时,一天 -->
   <property name="expires">
       <map key-type="java.lang.String" value-type="java.lang.Long">
           <entry key="halfHour" value="1800"/>
           <entry key="hour" value="3600"/>
           <entry key="oneDay" value="86400"/>
           <!-- shiro cache keys -->
           <entry key="authorizationCache" value="1800"/>
           <entry key="authenticationCache" value="1800"/>
           <entry key="activeSessionCache" value="1800"/>
       </map>
   </property>
</bean>

<!-- cache注解,和spring-ehcache.xml中的只能使用一个 -->
<cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>



项目中注解缓存只能配置一个,所以可以通过以下引入哪个配置文件来决定使用哪个缓存。


<import resource="classpath:spring/spring-ehcache.xml"/>
<!-- <import resource="classpath:spring/spring-redis.xml"/>-->



当然,可以通过其他配置搭配使用两个缓存机制。比如ecache做一级缓存,redis做二级缓存。


缓存对比.png


更加详细的使用与配置,可以参考项目中spring-shiro-training中有关spring cache的配置。

  • https://git.oschina.net/wangzhixuan/spring-shiro-training.git



推荐

让最好的人和最好的公司相遇,谈谈你对下一份工作的期待,扫码关注,你值得拥有。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值