SSM中如何使用redis

   redis是一个缓存服务器,使用键值对存储数据,由于redisweb系统交互的时候是在不同域(同主机但不同端口也算跨域,tomcat8080,而redis6379),需要进行不同组件之间的跨域请求,经过了网络传输,在这个过程中,需要缓存的对象必须实现序列化接口,请求双方才能正常处理请求或者回应。说了这么久,其实就是想说明使用redis,对象必须实现序列化。下面开始正式介绍redisSSM框架的配置!

  1.     使用maven导入依赖
<!-- spring的依赖 ,redis配置类需要扫描-->
<!-- Spring -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jms</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>
<!-- redis cache related.....start -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
<!-- redis cache related.....end -->
2.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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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/cache
                        http://www.springframework.org/schema/cache/spring-cache-4.2.xsd">

    <context:property-placeholder location="classpath:properties/redis.properties"/>

    <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 -->
    <cache:annotation-driven cache-manager="cacheManager"/>

    <!-- redis 相关配置 -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}"/>
        <property name="maxWaitMillis" value="${redis.maxWait}"/>
        <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
    </bean>

    <bean id="JedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/>

    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="JedisConnectionFactory"/>
    </bean>

    <!-- spring自己的缓存管理器,这里定义了缓存位置名称 ,即注解中的value -->
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <set>
                <!-- 这里可以配置多个redis -->
                <!-- <bean class="com.cn.util.RedisCache">
                     <property name="redisTemplate" ref="redisTemplate" />
                     <property name="name" value="default"/>
                </bean> -->
                <bean class="edu.mooc.utils.RedisCache">
                    <property name="redisTemplate" ref="redisTemplate"/>
                    <property name="name" value="common"/>
                    <!-- common名称要在类或方法的注解中使用 -->
                </bean>
            </set>
        </property>
    </bean>

</beans>

 
3.redis连接的属性文件
# Redis settings
# server IP
redis.host=127.0.0.1
# server port
redis.port=6379
# server pass
redis.pass=
# use dbIndex
redis.database=0
# 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例
redis.maxIdle=300
# 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间(毫秒),则直接抛出JedisConnectionException;  
redis.maxWait=3000
# 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的  
redis.testOnBorrow=true
4.将redis的配置文件加入到applicationContext-dao.xml文件中
 
 
<import resource="spring-redis.xml"></import>
原因:服务器启动的时候就会加载applicationContext-dao.xml这个文件,因为web.xml中设置了
contextConfigLocation,服务器启动就会加载这个这个配置下包含的配置文件。
 
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>

    亲测的结果是加到springmvc的配置文件中无效,如果说法有误,欢迎指正。
5.redis工具类(负责进行key的操作)
    
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;

public class RedisCache implements Cache {

    private RedisTemplate<String, Object> redisTemplate;
    private String name;

    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;
    }

    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return this.name;
    }

    @Override
    public Object getNativeCache() {
        // TODO Auto-generated method stub
        return this.redisTemplate;
    }

    @Override
    public ValueWrapper get(Object key) {
        // TODO Auto-generated method stub
        System.out.println("get key");
        final String keyf = key.toString();
        Object object = null;
        object = redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            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 (object != null ? new SimpleValueWrapper(object) : null);
    }

    @Override
    public void put(Object key, Object value) {
        // TODO Auto-generated method stub
        System.out.println("put key");
        final String keyf = key.toString();
        final Object valuef = value;
        final long liveTime = 86400;
        redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                byte[] keyb = keyf.getBytes();
                byte[] valueb = toByteArray(valuef);
                connection.set(keyb, valueb);
                if (liveTime > 0) {
                    connection.expire(keyb, liveTime);
                }
                return 1L;
            }
        });
    }

    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;
    }

    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;
    }

    @Override
    public void evict(Object key) {
        // TODO Auto-generated method stub
        System.out.println("del key");
        final String keyf = key.toString();
        redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                return connection.del(keyf.getBytes());
            }
        });
    }

    @Override
    public void clear() {
        // TODO Auto-generated method stub
        System.out.println("clear key");
        redisTemplate.execute(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection)
                    throws DataAccessException {
                connection.flushDb();
                return "ok";
            }
        });
    }

    @Override
    public <T> T get(Object key, Class<T> type) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ValueWrapper putIfAbsent(Object key, Object value) {
        // TODO Auto-generated method stub
        return null;
    }
}


6.在这里,我们使用注解的形式定义需要进行缓存操作

@Service
public class CourseServiceImpl implements CourseService {
    @Autowired
    private TCourseMapper courseMapper;
    @Autowired
    private TConstsClassifyMapper constsClassifyMapper;

    /**
     * 根据关键字查找课程
     *
     * @param keyWord
     */
    @Override
        //@CacheEvict(value="common",key="'id_'+#id")
        @CacheEvict(value="common",key="#keyWord")
    public List<TCourse> queryCourseByFuzzySerarch(String keyWord) {
        TCourseExample e = new TCourseExample();
        TCourseExample.Criteria criteria = e.createCriteria();
        /**
         * 模糊查找课程名+未被置为已删除的课程信息
         */
        criteria.andNameLike("%" + keyWord);
        criteria.andDelEqualTo(false);
        List<TCourse> courseList = courseMapper.selectByExample(e);
        return courseList;
    }

    /**
     * 根据ParentCode查询出该分类下的所有子分类
     *
     * @param parentCode
     * @return
     */

    @Override
    @Cacheable(value="common",key="#parentCode")
    public List<TConstsClassify> queryClassifyByParentCode(String parentCode) {
        TConstsClassifyExample e = new TConstsClassifyExample();
        TConstsClassifyExample.Criteria criteria = e.createCriteria();
        /**
         * ParentCode=parentCode
         * Del=false
         */
        criteria.andParentCodeEqualTo(parentCode);
        criteria.andDelEqualTo(false);
        List<TConstsClassify> clist = constsClassifyMapper.selectByExample(e);
        return clist;
    }
}

取两段段代码说明:
 
@Cacheable(value="common",key="#parentCode")
public List<TConstsClassify> queryClassifyByParentCode(String parentCode)
(1)@Cacheable主要针对方法配置,判断key在redis是否存在,若存在,则直接从redis中取,
 不存在则查数据库,再将结果放在缓存中并将结果返回
(2)value是缓存的名字,在redis的配置中必须制定一个,类似于一块空间,
  而这块空间中有许多key-value
(3)key是键,键的名字可以使用多种方式生成,比如key="#parentCode",
 就是key名以参数列表中的parentCode为名,#不能丢。
 如果不填key,默认是由下面的参数表组合而成的。
  假如需要起一个固定的名字,使用key="'xxx'"即可,比如查询所有班级学生的信息,使用key="'studentAll'"

@CacheEvict(value="common",key="#keyWord")
             public List<TCourse> queryCourseByFuzzySerarch(String keyWord)
            (1)@CacheEvict设置key过期,在key值与数据库的值即将不同步的时候执行
       (2)value是缓存的名字,在redis的配置中必须制定一个,类似于一块空间,
          而这块空间中有许多key-value

       (3)key是键,在这里意思是删除key与keyWord的值相同的key

总结:redis的同步策略的 两种方式:

1. 主动缓存过期时间,比如5分钟,5分钟后数据在redis清除
2. 主动更新,就是存放在redis中数据不设置过期时间,当数据发生变化时主动更新缓存 
第一种的话不能避免脏数据,第二种显得更好
部分效果结果展示:

    1.第一次访问:(数据库),并加入了缓存

                                                  

 

       2.第二次缓存:(走的缓存)

       3.执行key的过期操作后


参考博文:https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/index.html

                 https://blog.csdn.net/aqsunkai/article/details/51758900

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值