ssm整合Redis做mybatis二级缓存

1.redis配置

cmd命令进入redis的根目录

 选择redis根据那个配置文件启动,在其根目录中有两个配置文件,

一般选择redis.windows-service.conf

redis.windows.conf以非系统服务方式启动程序使用的配置文件

 启动成功如图

 2.ssm整合redis

           1.pom文件添加依赖:


<properties>
    <spring.version>4.3.3.RELEASE</spring.version>
    <spring.data.redis.version>1.5.0.RELEASE</spring.data.redis.version>
    <redis.clients.version>2.5.0</redis.clients.version>
</properties>
<!-- redis -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>${spring.data.redis.version}</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>${redis.clients.version}</version>
</dependency>

        2.配置文件:

        (1.)添加redis的配置信息文件redis.properties,根据项目中redis的实际情况进行配置

         (2.)在applicationContext.xml配置redis

                在此处需要注意的有几点:

                1.  property 用于加载类时,要用ref,不能用value,否则会报错

                2.  静态方法和静态属性无法通过 @Autowired 注解注入,因为静态属性和静态方法是属于类的方法,而不是实体的方法,其在类加载的过程就会创建,而 @Autowired 是从 spring  容器中加载注入

                3.@Autowired 注解在方法上,实际上和注解在属性上是同理的,注解在属性上是通过属性的setter方法注入,注解在方法中,方法名也必须是setter形式,只是方法里面我们可以做其他的操作

                假如我们的 RedisUtil 中的方法是静态方法,那么在该类中RedisTemplate就为静态属性,不能通过@Autowired 来注入如下xml中配置的 redisTemplate 类,就需要我们配置一个辅助类,用于注入 redisTemplate, xml中如下配置RedisHelper类


<!--加载所有的properties配置文件  jdbc配置,redis配置-->
<context:property-placeholder location="classpath*:*.properties"/>

<!--redis连接池配置,加载redis.properties文件获取数据-->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxTotal" value="${redis.maxTotal}" />
        <property name="minIdle" value="${redis.minIdle}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
    <!--配置redis连接工厂类,从redis.properties文件中获取数据,配置数据源,加载redis连接池-->
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.host}"/>
        <property name="port" value="${redis.port}"/>
        <property name="password" value="${redis.password}"/>
        <property name="poolConfig" ref="poolConfig"/>
    </bean>
<!--配置redis模板类,加载redis连接工厂,配置序列化方式-->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory"></property>
        <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        </property>
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        </property>
        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        </property>
        <property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        </property>
    </bean>
<!--配置一个redisHelper类用于加载redisTemplate-->
    <bean id="redisHelper" class="com.cl.redis.RedisHelper">
        <property name="redisTemplate" ref="redisTemplate"/>
    </bean>

                 java代码如下:

@Component
public class RedisHelper {

    @Autowired
    public void setRedisTemplate(RedisTemplate redisTemplate){
        RedisUtil.setRedisTemplate(redisTemplate);
    }
}


-------------------------------------------------------------------------------------

//只写了一个方法用于测试,可以根据自己的项目情况自行修改
//假如不用静态方法的话,直接在此类的属性 RedisTemplate 上添加 @Autowried 注解即可
//上面的辅助类可不要,同时xml中也不需要配置此类
public class RedisUtil {

    private static RedisTemplate redisTemplate;

    public static void  setRedisTemplate(RedisTemplate redisTemplate){
        RedisUtil.redisTemplate = redisTemplate;
    }

    public static String get(String key) throws Exception{
        String value = null;
        try{
            value = (String) redisTemplate.opsForValue().get(key);
        }catch (Exception e){
            e.printStackTrace();
            throw new BaseException("redis获取val错误");
        }
        return value;
    }
}

         测试:

   

 这是普通的redis应用,下面我们来看如何用redis做mybatis的二级缓存

        mybatis本身也有缓存

        一级缓存是sqlSession(sql会话)级别的,使用SelSession第一次查询后,MyBatis会将其放在缓存中,再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库,一级缓存是默认开启的

        二级缓存是application级别的,默认是不开启的,mybatis默认的二级缓存有一个缺点,它是保存在Mapper对象中的,在有一张A表,两个Mapper文件,AMapper.xml和BMapper.xml,B通过外键修改了A表中的内容,A是感知不到的,那么再从A里查询如果用到了缓存,就是旧的数据,因此在项目中一般用redis做mybatis的二级缓存

        mybatis提供了一个接口 Cache ,我们只需要继承这个接口就可以对接redis的二级缓存

package org.apache.ibatis.cache;

import java.util.concurrent.locks.ReadWriteLock;

public interface Cache {
    String getId();

    void putObject(Object var1, Object var2);

    Object getObject(Object var1);

    Object removeObject(Object var1);

    void clear();

    int getSize();

    default ReadWriteLock getReadWriteLock() {
        return null;
    }
}

那么我们创建一个类 RedisMybatisCache 继承 Cache

public class RedisMybatisCache implements Cache {

    private final Logger logger = LoggerFactory.getLogger(RedisMybatisCache.class);

    private String id;

    private static RedisTemplate redisTemplate;

    private final ReadWriteLock rwl = new ReentrantReadWriteLock();

    /**
     * 初始化 mybatis 二级缓存
     * @param id
     * @throws Exception
     */
    public RedisMybatisCache(String id) throws Exception{
        if(id == null){
            throw new BaseException("mybatis缓存初始化需要一个id");
        }
        this.id = id;
    }

    public static void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisMybatisCache.redisTemplate = redisTemplate;
    }

    @Override
    public String getId() {
        return this.id;
    }

    @Override
    public void putObject(Object o, Object o1) {
        try{
            redisTemplate.opsForValue().set(o.toString(),o1);
        }catch(Exception e){
            e.printStackTrace();
            logger.info("添加到mybatis缓存失败");
        }
    }

    @Override
    public Object getObject(Object o) {
        try{
            return redisTemplate.opsForValue().get(o.toString());
        }catch(Exception e){
            e.printStackTrace();
            logger.info("获取mybatis缓存失败");
        }
        return null;
    }

    @Override
    public Object removeObject(Object o) {
        try{
            redisTemplate.delete(o.toString());
        }catch(Exception e){
            e.printStackTrace();
            logger.info("从mybatis缓存移除失败");
        }
        return null;
    }

    @Override
    public void clear() {
        try{
            redisTemplate.delete(getId());
        }catch (Exception e){
            logger.info("刷新mybatis失败");
        }
    }

    @Override
    public int getSize() {
        return redisTemplate.keys("*").size();
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return rwl;
    }
}

同上面讲到的一样,我们需要将redisTemplate注入到缓存类  RedisMybatisCache  中,通过 RedisMybatisCacheBridge进行静态注入 

<!--redis做mybatis二级缓存配置-->
    <bean id="redisMybatisCacheBridge" class="com.cl.redis.RedisMybatisCacheBridge">
        <property name="redisTemplate" ref = "redisTemplate"/>
    </bean>
/**
 * 静态注入中间类
 */
@Component
public class RedisMybatisCacheBridge {

   @Autowired
    public void setRedisTemplate(RedisTemplate redisTemplate){
        RedisMybatisCache.setRedisTemplate(redisTemplate);
    }

}

然后我们需要去mapper里面开启缓存

<!--使用Redis缓存作为MyBatis二级缓存-->
    <cache type="com.cl.redis.RedisMybatisCache"/>

运行一下,然后报错,最后发现是序列化的问题,上面的applicationContext.xml文件中,我们有配redis中序列化的方式为 StringRedisSerializer,实际上它在序列化对象的时候会报错,因此我们需要修改value的序列化方式,百度了一波,全都是在java文件中配置,然后通过注解加载,我也没有找到好的在xml文件中配置的方法,只有把xml中注释掉,然后在上面所写的 RedisMybatisCache 类中的 setRedisTemplate() 方法中修改它的序列化方式,如果各位大佬有好的办法,请留言......

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

       <!--<property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        </property>
        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        </property>-->

        <!--<property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.GenericToStringSerializer"> </bean>
        </property>
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        </property>-->
        <!--开启事务  -->
        <property name="enableTransactionSupport" value="true"></property>
    </bean>
public static void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisMybatisCache.redisTemplate = redisTemplate;
        // 设置key和hash的field
        // 设置键(key)的序列化采用StringRedisSerializer。
        StringRedisSerializer stringRedisSerializer=new StringRedisSerializer();
        RedisMybatisCache.redisTemplate.setKeySerializer(stringRedisSerializer);
        RedisMybatisCache.redisTemplate.setHashKeySerializer(stringRedisSerializer);

        //下面这个效率低,不过可以反序列化带泛型的list数据
        //GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        //而这个方法,效率高,不过也要做一定的设定
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        // 设置值(value)的序列化采用FastJsonRedisSerializer。
        RedisMybatisCache.redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        RedisMybatisCache.redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        RedisMybatisCache.redisTemplate.afterPropertiesSet();
        //开启事务
        RedisMybatisCache.redisTemplate.setEnableTransactionSupport(true);
    }

 最终通过测试:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值