spring cache+redis

redis 依赖的jar包:
commons-pool2-2.5.0.jar
jedis-2.9.0.jar
spring-data-redis-1.6.2.RELEASE.jar
我是配合spring4.2实现的缓存操作:我这里实现spring cache+redis,spring自带的cache+redis实现的缓存,redis的配置加载spring里进行配置;配置内容:



<?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:aop="http://www.springframework.org/schema/aop" 
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:task="http://www.springframework.org/schema/task" 
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-4.2.xsd  
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd 
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd  
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
           http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.2.xsd">


<!-- 配置自动识别注解 -->
    <context:component-scan base-package="com.dome" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!-- <task:annotation-driven/> -->
    <task:annotation-driven executor="asyncExecutor" scheduler="scheduler"/>
  <task:executor id="asyncExecutor" pool-size="100-1000" queue-capacity="10000" rejection-policy="CALLER_RUNS"/>

  <task:scheduler id="scheduler" pool-size="100" />


    <!--加载数据库配置文件-->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="locations">
           <list>
              <!-- 加载数据库连接设置 -->
  <value>classpath:config/database.properties</value>
  <!-- <value>classpath:config/database.properties</value> -->
  <!-- 加载redis连接设置 -->
  <value>classpath:config/redis.properties</value>
          </list>
      </property>
    </bean>
    
<!-- 数据中心连接  就是数据库连接设置 我是封装在一个文件里的  暂不提供-->   
<import resource="datasource-sqlserver.xml" /> 
<!-- spring ehcache+redis 缓存设置 2个以上缓存组合使用-->
<import resource="spring-cache.xml" />

    <!-- 解决使用@ResponseBody 的中文乱码。 --> 
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
        <property name="messageConverters">  
            <list>  
                <!-- JSON解析对象 -->
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" >
                <property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
                </bean>  
                <bean class="org.springframework.http.converter.StringHttpMessageConverter">  
                    <property name="supportedMediaTypes">  
                        <list>  
                            <value>text/plain;charset=UTF-8</value>  
                        </list>  
                    </property>  
                </bean>  
            </list>  
        </property>
         <!-- 日期格式转换 -->
    <property name="webBindingInitializer">    
        <bean class="com.dome.filter.DateConverterFilter" />    
    </property>    
    </bean>
 
  <bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">  
  <!-- 验证码  kaptcha-->
        <property name="config">  
            <bean class="com.google.code.kaptcha.util.Config">  
                <constructor-arg>  
                    <props>  
                        <prop key="kaptcha.border">yes</prop>  
                        <prop key="kaptcha.border.color">105,179,90</prop>  
                        <prop key="kaptcha.textproducer.font.color">blue</prop>  
                        <prop key="kaptcha.image.width">125</prop>  
                        <prop key="kaptcha.image.height">45</prop>  
                        <prop key="kaptcha.textproducer.font.size">45</prop>  
                        <prop key="kaptcha.session.key">kaptchaRemote</prop>  
                        <prop key="kaptcha.textproducer.char.length">4</prop>  
                        <prop key="kaptcha.textproducer.font.names">宋体,楷体,微软雅黑</prop>  
                    </props>  
                </constructor-arg>  
            </bean>  
        </property>  
    </bean>  
</beans>

mybatisConfig.xml:redis 缓存配置


<?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:aop="http://www.springframework.org/schema/aop" 
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:task="http://www.springframework.org/schema/task" 
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-4.2.xsd  
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd 
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd  
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
           http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.2.xsd">


    <!-- * 优势:简单直观,效率高
         * 劣势:系统中只能用Redis一种缓存了 
                               使用redis内置CacheManager-->
         
<!-- jedis 配置  连接池配置-->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
     <!-- #最大空闲数   -->
<property name="maxIdle" value="${redis.maxIdle}" />
<!-- #控制一个pool可分配多少个jedis实例 -->
<property name="maxTotal" value="${redis.maxTotal}" />  
<!-- #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。 -->
<property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
<!-- #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个 -->
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
 
<!-- redis服务器中心  连接redis基本信息-->
<bean id="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="poolConfig" ref="poolConfig" />
<property name="port" value="${redis.port}" />
<property name="hostName" value="${redis.host}" />
<property name="password" value="${redis.password}" />
<!-- #客户端超时时间单位是毫秒 默认是2000 -->
<property name="timeout" value="${redis.timeout}"></property>
<!-- #选择redis第几个库 -->
<property name="database" value="${redis.database}" />
</bean>
 
<!-- redis template,被后面的RedisCacheManager或RedisCache引用 --> 
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
  <!--开启事务  -->  
          <property name="enableTransactionSupport" value="true"/>
          <!--value,key值 的序列化  Redis缓存对象乱码处理-->
  <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
          </property>
         <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
         </property>


         <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
         </property>
         <property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
         </property>
         <property name="stringSerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
         </property>
</bean>
 
 
<!-- 配置缓存 -->
<cache:annotation-driven cache-manager="cacheManager" />
<!-- 前面一样,仅替换掉cacheManager的定义 -->  
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">      
    <property name="caches">      
        <set> 
                    <!-- 自带的缓存实现类 -->   
            <bean class="org.springframework.data.redis.cache.RedisCache"><!-- 这个类没有默认构造方法   -->
                <constructor-arg index="0" name="name">
                           <value>user1</value><!-- 缓存名,在注解中用value引用       -->
                </constructor-arg><!-- 缓存名,在注解中用value引用   -->
                <constructor-arg index="1" name="prefix"><null/></constructor-arg>  
                <constructor-arg index="2" name="redisOperations"><ref  bean="redisTemplate"/></constructor-arg>  
                <!-- 设置超时时间 -->  
                <constructor-arg index="3" name="expiration"><value>3600</value></constructor-arg>  
            </bean>
                         <!-- SystemRedisCache  这个是自定义的缓存实现类 -->          
                <bean class="com.dome.util.redis.SystemRedisCache">    
                     <property name="redisTemplate" ref="redisTemplate" />    
                     <property name="name" value="users"/> 
               <!-- 自定义的缓存实现类参数 超时时间 -->  
                      <property name="timeout" value="600" />   
                     <!-- name对应的名称要在类或方法的注解中使用 -->  
                </bean> 
        </set>      
     </property>      
</bean>
</beans>


SystemRedisCache 自定义缓存类实现

package com.dome.util.redis;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.google.gson.Gson;
public class SystemRedisCache implements Cache {


/*
* 自定义缓存策略
*/


// redis连接
private RedisTemplate<String, Object> redisTemplate;
// 缓存 缓存名
private String name;
// 超时时间
private long timeout;
// redis 自带的字符串序列化
private StringRedisSerializer serializer=new StringRedisSerializer();




public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}


public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}


public void setName(String name) {
this.name = name;
}


public String getName() {
return this.name;
}


public long getTimeout() {
return timeout;
}


public void setTimeout(long timeout) {
this.timeout = timeout;
}


@Override
public Object getNativeCache() {
return this.redisTemplate;
}


// 获取缓存
@Override
public ValueWrapper get(Object key) {
final String keyf = (String) key;// key 值
Object object = null;// 键值
object = redisTemplate.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {


byte[] key = keyf.getBytes();
byte[] value = connection.get(key);
if (value == null) {
return null;
}
//connection.close();
return toObject(value);
//return serializer.deserialize(value);
}
});

return (object != null ? new SimpleValueWrapper(object) : null);
}


// 添加缓存
@Override
public void put(Object key, Object value) {
final String keyf = (String) key;// key 值
final Object valuef = value;// 键值
redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
byte[] keyb = keyf.getBytes();
byte[] valueb = toByteArray(valuef); //对象转换成字节数组  redis转换成乱码
//connection.setClientName(serializer.serialize(name));
//connection.setEx(toByteArray(name), 1, keyb);
System.out.println("name:---------------------"+getName());
connection.set(keyb, valueb);
//connection.
/*if (timeout > 0) {
// 设置超时时间
connection.expire(keyb, timeout);
}*/
//connection.close();
return 1L;
}
});
}


/**
* 描述 : <Object转byte[]>. <br>
* <p>
* <使用方法说明>
* </p>

* @param obj
* @return
*/
@SuppressWarnings("unused")
private byte[] toByteArray(Object obj) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray();
oos.close();
bos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return bytes;
}


/**
* 描述 : <byte[]转Object>. <br>
* <p>
* <使用方法说明>
* </p>

* @param bytes
* @return
*/
private Object toObject(byte[] bytes) {
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
obj = ois.readObject();
ois.close();
bis.close();
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
return obj;
}


// 根据Key 删除缓存
@Override
public void evict(Object key) {
final String keyf = (String) key;// key 值
redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.del(keyf.getBytes());
}
});
}


// 清空缓存
@Override
public void clear() {
redisTemplate.execute(new RedisCallback<String>() {
public String doInRedis(RedisConnection connection) throws DataAccessException {
connection.flushDb();
return "ok";
}
});
}


@SuppressWarnings("unchecked")
@Override
public <T> T get(Object key, Class<T> type) {
final String keyf = (String) key;
Object object = null;
object = redisTemplate.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {


byte[] key = keyf.getBytes();
byte[] value = connection.get(key);
if (value == null) {
return null;
}
return toObject(value);
}
});
return (T) object;
}


@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
put(key, value);
return new SimpleValueWrapper(value);
}






}


伪代码验证 按自己需求添加代码 (谨做参考):
伪代码:
package com.dome.service.user.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.dome.bean.user.User;
import com.dome.dao.source2.user.UserMapper;
import com.dome.service.user.UserService;

@Service
public class UserServiceImpl implements UserService {
/**
* userService

* 缓存机制说明:所有的查询结果都放进了缓存,也就是把MySQL查询的结果放到了redis中去,
* 然后第二次发起该条查询时就可以从redis中去读取查询的结果,从而不与MySQL交互,从而达到优化的效果,
* redis的查询速度之于MySQL的查询速度相当于 内存读写速度/硬盘读写速度
* @Cacheable("a")注解的意义就是把该方法的查询结果放到redis中去,
* 下一次再发起查询就去redis中去取,存在redis中的数据的key就是a;
* @CacheEvict(value={"a","b"},allEntries=true)
* 的意思就是执行该方法后要清除redis中key名称为a,b的数据;
* key 命名规范
* 当前被调用的方法使用的Cache:#root.caches[0].name
* 当前方法名#root.methodName  当前方法#root.method.name 当前被调用的对象#root.target 当前被调用的对象的     * class#root.targetClass
* 当前方法参数组成的数组#root.args[0] 当前被调用的方法使用的Cache#root.caches[0].name */
@Autowired
private UserMapper userMapper;

@Cacheable(value="users",key="'test'")
@Override
public User selectOne(String id) {
return userMapper.selectOne(id);
}

        //allEntries=true  这里暂没有添加实现  
    //去除该缓存名所有的缓存
@CacheEvict(value="users",key="'test'")
@Override
public Boolean updateOne(String id) {
try {
User u = userMapper.selectOne(id);
u.setId("1");
u.setUsername("qwer1234");
userMapper.updateByPrimaryKeySelective(u);
return true;
}catch (Exception e) {
e.printStackTrace();
}
return false;
}
}

缺点:
缓存的value,key都在service层的注解里 不便于后期维护
redis缓存容易出现更新和查询缓存同步执行 出现脏数据的问题
项目中不建议这样使用 怎么写后面会有介绍---------我们先了解 在优化


这样的spring cache +redis 的缓存 本人觉得难用 项目中 不建议这样实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ctrl+C+V程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值