Springboot+Mybatis+Redis实现二级缓存

本文介绍如何将MyBatis与Redis集成以实现二级缓存功能,包括配置步骤、序列化处理及日志输出等关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二级缓存是多个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缓存中获取的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值