SSM+Redis,使用Redis作为mybatis的二级缓存

       本文主要介绍将ssm项目与Redis进行整合,使用Redis作为缓存。其原理就是实现mybatis的自定义缓存,mybatis允许我们使用自定义的缓存来作为它的二级缓存,只需要实现它的Cache接口即可。
主要步骤如下:
0.ssm项目搭建(本文省略)
1.pom.xml里引入依赖
2.配置Redis的链接
3.自定义实现Cache

在这里可以根据自己的业务需要去实现cache。如:网上很多示例在clear时,使用flushDb(),这样会把所有缓存清除!而我只想删除相应mapper下的缓存,因此使用了list来存储和删除缓存,但是这样要注意在多表查询时会出现的脏数据等问题。

4.在mapper里开启二级缓存


1.pom.xml

加入Redis的依赖


          redis.clients
          jedis
          2.9.0
      
      
          org.springframework.data
          spring-data-redis
          1.6.2.RELEASE


2.Redis配置

在spring的配置文件里加入


        
            
                classpath:redis.properties
            
        
    

    
    
        
        
        
        
    
    
    
    
    
        
    

redis.properties如下

# Redis settings
redis.host=localhost
redis.port=6379  
redis.pass=

redis.maxIdle=300  
redis.maxActive=600  
redis.maxWait=1000  
redis.testOnBorrow=true

3.自定义cache

在这里定义一个RedisCache类,根据自己的需要去实现Cache,分别是:
·String getId();//获取id
·void putObject(Object var1, Object var2);//写入缓存
·Object getObject(Object var1);//获取缓存
·Object removeObject(Object var1);//删除缓存
·void clear();//清空缓存
·int getSize();//获取大小
·ReadWriteLock getReadWriteLock();//获取ReadWriteLock
 
注意:
当进行insert、update操作时,会先去清空缓存,也就是调用clear方法,如果使用的是redisConnection.flushDb(),这样会把所有的缓存都清除,不符合我的需求。
 

我的方式:
因为每个namespace下的cache的id是不同的,每当调用putObject写入缓存时,可以使用一个list,将其key都存储在当前id的list下,当执行clear时,清除这个list下的缓存即可

    
具体代码如下:

public class RedisCache implements Cache {
    @Autowired
    private static JedisConnectionFactory jedisConnectionFactory;

    private String id;

    private static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public RedisCache(String id) {
        if (id == null) {
            throw new IllegalArgumentException("id is null");
        }
        this.id = id;
    }

    public RedisCache() {

    }

    public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
        RedisCache.jedisConnectionFactory = jedisConnectionFactory;
    }

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

    @Override
    public void putObject(Object key, Object value) {
        JedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
            connection.set(serializer.serialize(key), serializer.serialize(value));
            connection.lPush(serializer.serialize(id),serializer.serialize(key));
            System.out.println("写入缓存:" + key + "," + value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    @Override
    public Object getObject(Object key) {
        Object res = null;
        JedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
            res = serializer.deserialize(connection.get(serializer.serialize(key)));
            if (res != null) {
                System.out.println("获取缓存数据:" + res.toString());
            } else {
                System.out.println("当前没有缓存:" + key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        return res;
    }

    @Override
    public Object removeObject(Object key) {
        Object res = null;
        JedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
            res = connection.expire(serializer.serialize(key), 0);
            connection.lRem(serializer.serialize(id),0,serializer.serialize(key));
            System.out.println("删除缓存:" + key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        return res;
    }

    @Override
    public void clear() {
        JedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
//            connection.flushDb();
//            connection.flushAll();
            Long length = connection.lLen(serializer.serialize(id));
            if (0 == length) {
                return;
            }
            List<byte[]> keys = connection.lRange(serializer.serialize(id),0,length-1);
            for (byte[] key :keys) {
                connection.expireAt(key,0);
                System.out.println("删除缓存:"+serializer.deserialize(key).toString());
            }
            connection.expireAt(serializer.serialize(id),0);
            keys.clear();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    @Override
    public int getSize() {
        int result = 0;
        JedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            result = Integer.valueOf(connection.dbSize().toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        return result;
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }
}


4.开启二级缓存

在mapper里加入:



测试

准备了两个类:Test和Test2,分别对应两个不同的namespace
做如下操作:
1.分别查询Test和Test2
2.再次查询Test和Test2
3.对Test做修改操作
4.查询Test和Test2
得到如下打印结果:
SSM+Redis,使用Redis作为mybatis的二级缓存_第1张图片

从上面的打印结果可以看到:

  • 当第一次查询的时候,没有缓存,会往Redis写入缓存
  • 再次进行查询的时候,直接获取缓存数据
  • 对Test进行修改时,会删除Test的缓存
  • 再次查询的时候,Test会重新写入缓存,而Test2仍然在缓存中

这样清空缓存的作用域就是所在的namespace了;
如果使用redisConnection.flushDb()的话,有修改的时候Test和Test2的缓存都会被删除;
但是尽量不要使用多表操作,避免脏数据等问题。


代码下载:
https://github.com/fi00wind/ssm-redis

你可能感兴趣的:(spring,redis,mybatis)