ssm整合Redis做mybatis二级缓存

1.redis配置

cmd命令进入redis的根目录

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

一般选择redis.windows-service.conf

redis.windows.conf以非系统服务方式启动程序使用的配置文件ssm整合Redis做mybatis二级缓存_第1张图片

 启动成功如图

ssm整合Redis做mybatis二级缓存_第2张图片

 2.ssm整合redis

           1.pom文件添加依赖:



    4.3.3.RELEASE
    1.5.0.RELEASE
    2.5.0



    org.springframework.data
    spring-data-redis
    ${spring.data.redis.version}


    redis.clients
    jedis
    ${redis.clients.version}

        2.配置文件:

ssm整合Redis做mybatis二级缓存_第3张图片

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

ssm整合Redis做mybatis二级缓存_第4张图片

         (2.)在applicationContext.xml配置redis

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

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

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

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

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







        
        
        
        
    
    
    
        
        
        
        
    

    
        
        
            
        
        
            
        
        
            
        
        
            
        
    

    
        
    

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

ssm整合Redis做mybatis二级缓存_第5张图片

         测试:

ssm整合Redis做mybatis二级缓存_第6张图片

   ssm整合Redis做mybatis二级缓存_第7张图片

 这是普通的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进行静态注入 


    
        
    
/**
 * 静态注入中间类
 */
@Component
public class RedisMybatisCacheBridge {

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

}

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


    

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


        

       

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

 最终通过测试:

ssm整合Redis做mybatis二级缓存_第8张图片

你可能感兴趣的:(javaee,java-ee,redis,mybatis)