Springboot+Mybatis+Redis實現二級緩存

二級緩存是多個SqlSession共享的,其作用域是mapper的同一個namespace,不同的sqlSession兩次執行相同namespace下的sql語句且向sql中傳遞參數也相同即最終執行相同的sql語句,第一次執行完畢會將數據庫中查詢的數據寫到緩存(內存),第二次會從緩存中獲取數據將不再從數據庫查詢,從而提高查詢效率。

1.添加pom依賴

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-redis</artifactId>
</dependency>

2.添加redis配置類

@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Bean
    public JedisPoolConfig getRedisConfig(){
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxIdle(maxIdle);
        config.setMaxTotal(maxTotal);
        config.setMaxWaitMillis(maxWaitMillis);
        config.setMinIdle(minIdle);
        return config;
    }

    @Bean(name = "jedisConnectionFactory")
    public JedisConnectionFactory getConnectionFactory(){
        JedisConnectionFactory factory = new JedisConnectionFactory();
        JedisPoolConfig config = getRedisConfig();
        factory.setPoolConfig(config);
        factory.setHostName(host);
        factory.setPort(port);
        factory.setDatabase(database);
        factory.setPassword(password);
        factory.setTimeout(timeout);
        return factory;
    }

    @Bean(name = "redisTemplate")
    public RedisTemplate<?, ?> getRedisTemplate(){
        RedisTemplate<?,?> template = new StringRedisTemplate(getConnectionFactory());
        return template;
    }
}

3.在application.properties中配置redis

## Redis 配置
## Redis數據庫索引(默認爲0)
spring.redis.database=0
## Redis服務器地址
spring.redis.host=127.0.0.1
## Redis服務器連接端口
spring.redis.port=6379
## Redis服務器連接密碼(默認爲空)
spring.redis.password=
## 連接池最大連接數(使用負值表示沒有限制)
spring.redis.pool.max-active=8
## 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
## 連接池中的最大空閒連接
spring.redis.pool.max-idle=8
## 連接池中的最小空閒連接
spring.redis.pool.min-idle=0
## 連接超時時間(毫秒)
spring.redis.timeout=0

4.配置Redis作爲Mybatis的緩存

public class MybatisRedisCache implements Cache {


    private static JedisConnectionFactory jedisConnectionFactory;

    private static JedisPool pool;

    private final String id;

    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public MybatisRedisCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        this.id = id;
        pool = new JedisPool(jedisConnectionFactory.getPoolConfig(), jedisConnectionFactory.getHostName(), jedisConnectionFactory.getPort());
    }

    private Object execute(RedisCallback callback) {
        Jedis jedis = pool.getResource();

        Object var3;
        try {
            var3 = callback.doWithRedis(jedis);
        } finally {
            jedis.close();
        }

        return var3;
    }

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

    @Override
    public int getSize() {
        return (Integer) this.execute(new RedisCallback() {
            @Override
            public Object doWithRedis(Jedis jedis) {
                Map<byte[], byte[]> result = jedis.hgetAll(MybatisRedisCache.this.id.toString().getBytes());
                return result.size();
            }
        });
    }

    @Override
    public void putObject(final Object key, final Object value) {
        this.execute(new RedisCallback() {
            @Override
            public Object doWithRedis(Jedis jedis) {
                jedis.hset(MybatisRedisCache.this.id.toString().getBytes(), key.toString().getBytes(), SerializeUtil.serialize(value));
                return null;
            }
        });
    }

    @Override
    public Object getObject(final Object key) {
        return this.execute(new RedisCallback() {
            @Override
            public Object doWithRedis(Jedis jedis) {
                return SerializeUtil.unserialize(jedis.hget(MybatisRedisCache.this.id.toString().getBytes(), key.toString().getBytes()));
            }
        });
    }

    @Override
    public Object removeObject(final Object key) {
        return this.execute(new RedisCallback() {
            @Override
            public Object doWithRedis(Jedis jedis) {
                return jedis.hdel(MybatisRedisCache.this.id.toString(), new String[]{key.toString()});
            }
        });
    }

    @Override
    public void clear() {
        this.execute(new RedisCallback() {
            @Override
            public Object doWithRedis(Jedis jedis) {
                jedis.del(MybatisRedisCache.this.id.toString());
                return null;
            }
        });
    }

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

    @Override
    public String toString() {
        return "Redis {" + this.id + "}";
    }

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


}

5.通過RedisCacheTransfer靜態注入

@Component
public class RedisCacheTransfer {

    @Autowired
    public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
        MybatisRedisCache.setJedisConnectionFactory(jedisConnectionFactory);
    }

}

6.配置mapper作用域namespace

二級緩存的作用域是mapper的namespace,所以要在mapper中添加這句話

 <cache type="com.kangaroo.studio.moonlight.dao.cache.MybatisRedisCache"/>

7.實現model序列化

讀寫緩存Model需要序列化,只需要在類聲明的時候 implements Serializable 就好了。

8.配置logback.xml,控制檯查看sql語句

總結:

在第一次查詢的時候,可以在控制檯看到查詢的sql語句,當再次進行查詢的時候,控制檯不再輸出sql語句,此時數據是從redis緩存中獲取的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章