spring+redis做数据对象缓存

1.添加maven依赖

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.6.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.0</version>
        </dependency>
        <!-- 注意这里-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.6.6</version>
        </dependency>

对于jackson-databind的引用不是必须的。但是,如果你使用的是默认的jdk序列化器,那么要求你的缓存类必须实现Serializable接口。如果不想影响你的model的,又想使用json序列化器的话,那么这个依赖就需要加了。

2.添加spring配置文件

可以以spring-redis.xml命名

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/cache
        http://www.springframework.org/schema/cache/spring-cache.xsd">

    <context:component-scan base-package="com.pumpkin.carriage.service" />
    <context:property-placeholder location="classpath:redis.properties"/>

    <!-- turn on declarative caching -->
    <cache:annotation-driven cache-manager="cacheManager"/>

    <!-- Jedis ConnectionFactory -->
   <!--  <bean
        id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
        p:host-name="${redis.hostname}"
        p:port="${redis.port}"
        p:password="${redis.password}"
        p:use-pool="true"/> -->

    <bean
        id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.hostname}"></property>
        <property name="port" value="${redis.port}"></property>
        <property name="password" value="${redis.password}"></property>
    </bean>

    <!-- redis template definition -->
    <bean
        id="redisTemplate"
        class="org.springframework.data.redis.core.RedisTemplate"
        p:connection-factory-ref="jedisConnectionFactory" >
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
        </property>
        <!-- 1.注意这里 -->
        <property name="keySerializer">  
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
        </property> 
        </bean>

    <!-- declare Redis Cache Manager -->
    <bean
        id="cacheManager"
        class="org.springframework.data.redis.cache.RedisCacheManager">
        <constructor-arg name="redisOperations" ref="redisTemplate" /> 
   </bean>

</beans>

以下是redis.properties文件的内容:

redis.hostname=129.42.200.230
redis.port=7001
#2.注意这里
redis.password=456789

以上,第1个注意点,缓存对象key值的序列化形式的,如果这里不添加keySerializer,而是使用默认的话那么,在redis后台看到的key会是:“\xac\xed\x00\x05t\x00\tb”这样包含一个转码的前缀,是不是很不爽,是不是查看的时候会很不方便,所以这里必须要设置key的序列化器。
第2个注意点,是redis链接配置的,如果你的redis没有设置密码,那么这个地方可以不写,不过redis还是应该设置密码的吧,不然大门四开….

3.添加Cacheable注解

cacheable能够实现自动缓存接口的返回结果,所以我们可以把注解直接加到我们需要缓存结果的接口上。

放的位置可以试service也可以是dao,以下是放到service和dao层的示例:

放到service层上:

@Cacheable(value="workDetailV150",key="'workDetailV150'.concat(#param.workId.toString()).concat(#param.userId.toString())")
    public CliDresserWorkDetailV150 getWorkDetail(CliGetWorkDetailParam param) throws Exception {
        return doGetWorkDetail(param);
    }

放到dao层上:

    @Cacheable(value="getWorkDetailPhotos",key="'getWorkDetailPhotos'.concat(#root.args[0])")
    List<String> getWorkDetailPhotos(Integer workId);

有没有看到,两者的不同,在dao层上,因为用了mybatis的缘故,这里只有接口,那么用workId放到key里面是存不到redis的,因为spring cache拿到的是null。所以这里必须用#root.args[x]的方式设置。

问题来了,那个这里有一个value还有一个key,他们分别代表了什么呢?

上边这张图很好的说明了他们的作用,每一个key对应到一个缓存的对象实体,那么value呢?可以看做是一个分作,你缓存的所有key都可以在这里找到。图中的“zset”就是value对应的项,每一个省都是一个key对应的项。为什么要弄一个zset在这里多余?后边的弹出一章你就明白了。

这里有一个细节,如果我的service接口返回了很多内容,不想全部缓存,怎么办?这里不能直接定义内部方法,添加cacheable然后在一个service接口方法里调用。因为,不管你用的是private还是public在这里都不会缓存的,必须是直接被controller调用的接口,或者直接调用的另外一个注入的service的接口。这里我和海威有一些争议:我的想法是,既然都是get方法,那么直接在controller里面组装业务逻辑比较合适,他觉得在service里面调用其他service也无妨。

4.强制清除缓存

如果我们缓存的实体更新了,怎么办?不能够get的还是就的东西。这时候就需要强制清除相关联的缓存了。方法就是提供一个空的接口方法,在该方法上添加@CacheEvict的注解,如下:

@CacheEvict(value = "workDetailV150", allEntries=true)
    public void evictWorkDetailCache(){
    }

再到controller层的时候,该怎么做呢?这个你应该能够想到的…

5.cacheable注解中key表达式的说明

这个地方主要简单说明一下3个要素:1.字符串、2.接口参数、3.环境参数,以及一个函数
字符串很好说了用单引号括起来就可以了。
接口参数直接用#加参数名,如果是参数内的属性那么继续用.串联接好了。
环境参数:

属性名称描述示例
methodName当前方法名root.methodName
method当前方法root.method.name
target当前被调用的对象root.target
targetClass当前被调用的对象的classroot.targetClass
args当前方法参数组成的数组root.args[0]
caches当前被调用的方法使用的Cacheroot.caches[0].name

最后是关键函数concat,意思很明白了,就是连接字符串用的。

6.重要连接

这是海威找到的一个特别好的贴子,将的很细致:http://haohaoxuexi.iteye.com/blog/2123030
这是spring-data-redis的官方文档:http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#redis:support:cache-abstraction
这是序列化器的一个贴子:http://www.360doc.com/content/15/0513/21/1073512_470277654.shtml
这是cacheable注解key表达式的一个stackoverflow上的贴子:http://stackoverflow.com/questions/11889428/spring-cacheable-with-complex-keys-still-executed
这是一个redis的命令集合,分类的特别好:http://doc.redisfans.com/

7.增大连接池的连接数

spring-data-redis的默认连接池连接数是8,十分小。使用时经常会出现could not get resource from the pool的情况,所以我们需要设置更大的连接数。

配置文件中首先需要增加一个连接池配置信息bean

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

接下来需要修改JedisConnectionFactory的配置,增加连接池配置bean的注入

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

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐