引言

目前很多系统为了解决数据读写的性能瓶颈,在系统架构设计中使用Redis实现缓存,Spring框架为了让开发人员更加方便快捷的使用Redis实现缓存,对Redis的操作进行了包装。

0.缓存

个人理解的缓存是指用于存储频繁使用的数据的空间,关注点是存储数据的空间和使用频繁的数据。缓存技术,简单的说就是先从缓存中查询数据是否存在,存在则直接返回,不存在再执行相应的操作获取数据,并将获取的数据存储到缓存中,它是一种提升系统性能的重要方法。

1.Redis

Redis是一个开源的、内存存储key-value类型的数据结构服务器,可用作数据库、高速缓存和消息队列代理。它支持的数据类型有字符串、哈希表、列表、集合、有序集合等,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供分区功能。

2.jedis

jedis是Redis的Java版客户端实现,也是官方推荐的Java版客户端。它封装了对Redis的各种操作,并且支持事务、管道及有jedis自身实现的分布式。

3.Spring Data Redis

Spring Data是Spring框架中的一个主要项目,目的是为了简化构建基于Spring框架应用的数据访问,包括非关系数据库、Map-Reduce框架、云数据服务等,另外也包含对关系数据库的访问支持。
Spring Data Redis是Spring Data项目中的一个主要模块,实现了对jedis客户端API的高度封装,使对Redis的操作更加便捷。

4.关系图

Redis、jedis、Spring Data Redis三者之间的关系图如下所示。

\"\"

5.Spring Cache

从Spring3.1开始,Spring框架提供了对Cache的支持,提供了一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的作用。提供的主要注解有@Cacheable、@CachePut、@CacheEvict和@Caching,具体见表1。

\"\"

@Cacheable的常用属性及说明如表2所示。

\"\"

\"\"

@CacheEvict的常用属性见表4。@CachePut的常用属性同@Cacheable。

\"\"

当需要在类上或方法上同时使用多个注解时,可以使用@Caching,如@Caching(cacheable = @Cacheable(\"User\"), evict = {@CacheEvict(\"Member\"), @CacheEvict(value = \"Customer\", allEntries = true)})

6.使用示例

下面使用Spring Data Reds、Redis和jedis实现一个简单的数据缓存。

1)依赖配置

示例使用了gradle,所以需要在build.gradle中加入如下依赖配置来管理所需要的jar。

compile \"org.spring work.data:spring-data-redis:1.7.2.RELEASE\"
compile \"redis.clients:jedis:2.7.2\"
testCompile \"junit:junit:4.12\"

2)Redis配置

示例连接的是本地的Redis,redis.properties配置如下。

# Redis settings
redis.host=127.0.0.1
redis.port=6379
redis.pass=
redis.dbIndex=0
redis.expiration=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true

3)Spring配置

Spring的配置文件如下。

<?  version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
<beans  ns:xsi=\"http://www.w3.org/2001/ Schema-instance\"
     ns=\"http://www.spring work.org/schema/beans\"
     ns:context=\"http://www.spring work.org/schema/context\"
     ns:cache=\"http://www.spring work.org/schema/cache\"
    xsi:schemaLocation=\"http://www.spring work.org/schema/beans
    http://www.spring work.org/schema/beans/spring-beans.xsd
    http://www.spring work.org/schema/context http://www.spring work.org/schema/context/spring-context.xsd
    http://www.spring work.org/schema/cache http://www.spring work.org/schema/cache/spring-cache.xsd\">
  <context:component-scan  -package=\"redis.cache\"/>
  <context:annotation-config/>
  <cache:annotation-driven cache-manager=\"redisCacheManager\"/>
  <bean class=\"org.spring work.beans.factory.config.PropertyPlaceholderConfigurer\">
    <property name=\"locations\">
      <list>
        <value>classpath:redis.properties</value>
      </list>
    </property>
  </bean>
  <!-- 配置JedisPoolConfig实例 -->
  <bean id=\"poolConfig\" class=\"redis.clients.jedis.JedisPoolConfig\">
    <property name=\"maxIdle\" value=\"${redis.maxIdle}\"/>
    <property name=\"maxTotal\" value=\"${redis.maxActive}\"/>
    <property name=\"maxWaitMillis\" value=\"${redis.maxWait}\"/>
    <property name=\"testOnBorrow\" value=\"${redis.testOnBorrow}\"/>
  </bean>
  <!-- 配置JedisConnectionFactory -->
  <bean id=\"jedisConnectionFactory\" class=\"org.spring work.data.redis.connection.jedis.JedisConnectionFactory\">
    <property name=\"hostName\" value=\"${redis.host}\"/>
    <property name=\"port\" value=\"${redis.port}\"/>
    <property name=\"password\" value=\"${redis.pass}\"/>
    <property name=\"data \" value=\"${redis.dbIndex}\"/>
    <property name=\"poolConfig\" ref=\"poolConfig\"/>
  </bean>
  <!-- 配置RedisTemplate -->
  <bean id=\"redisTemplate\" class=\"org.spring work.data.redis.core.RedisTemplate\">
    <property name=\"connectionFactory\" ref=\"jedisConnectionFactory\"/>
  </bean>
  <!-- 配置RedisCacheManager -->
  <bean id=\"redisCacheManager\" class=\"org.spring work.data.redis.cache.RedisCacheManager\">
    <constructor-arg name=\"redisOperations\" ref=\"redisTemplate\"/>
    <property name=\"defaultExpiration\" value=\"${redis.expiration}\"/>
  </bean>
</beans>

4)Service

示例代码的Servicer如下。

@Service(\"userService\")
public class UserService {
  @Cacheable(value = \"User\", key = \"\'UserId_\' + #id\",condition = \"#id<=110\")
  public String queryFullNameById(long id) {
    System.out.println(\"execute queryFullNameById method\");
    return \"ZhangSanFeng\";
  }

  @CacheEvict(value = \"User\", key = \"\'UserId_\' + #id\")
  public void deleteById(long id) {
    System.out.println(\"execute deleteById method\");
  }

  @CachePut(value = \"User\", key = \"\'UserId_\' + #id\")
  public String modifyFullNameById(long id, String newName) {
    System.out.println(\"execute modifyFullNameById method\");
    return newName;
  }
}

5)测试

  @Test
  public void test() {
    ApplicationContext context = new ClassPath ApplicationContext(\"redisCacheContext. \");
    UserService userService = (UserService) context.getBean(\"userService\");
    System.out.println(\"第一次执行查询:\" + userService.queryFullNameById(110L));
    System.out.println(\"----------------------------------\");

    System.out.println(\"第二次执行查询:\" + userService.queryFullNameById(110L));
    System.out.println(\"----------------------------------\");

    userService.deleteById(110L);
    System.out.println(\"----------------------------------\");

    System.out.println(\"清除缓存后查询:\" + userService.queryFullNameById(110L));
    System.out.println(\"----------------------------------\");

    System.out.println(userService.modifyFullNameById(110L, \"ZhangJunBao\"));
    System.out.println(\"----------------------------------\");

    System.out.println(\"修改数据后查询:\" + userService.queryFullNameById(110L));
    System.out.println(\"----------------------------------\");

    System.out.println(\"第一次执行查询:\" + userService.queryFullNameById(112L));
    System.out.println(\"----------------------------------\");

    System.out.println(\"第二次执行查询:\" + userService.queryFullNameById(112L));
    System.out.println(\"----------------------------------\");
  }

6)测试结果

输出结果如下。

execute queryFullNameById method
第一次执行查询:ZhangSanFeng
----------------------------------
第二次执行查询:ZhangSanFeng
----------------------------------
execute deleteById method
----------------------------------
execute queryFullNameById method
清除缓存后查询:ZhangSanFeng
----------------------------------
execute modifyFullNameById method
ZhangJunBao
----------------------------------
修改数据后查询:ZhangJunBao
----------------------------------
execute queryFullNameById method
第一次执行查询:ZhangSanFeng
----------------------------------
execute queryFullNameById method
第二次执行查询:ZhangSanFeng
----------------------------------

从结果可以看到,使用缓存后,第二次查询没有执行查询方法体,直接返回了缓存中的数据;清除缓存后,再次查询就执行了查询方法体;修改数据后,相应的缓存数据也被修改了;不符合缓存条件的数据没有被缓存。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

收藏 打印