SpringBoot+Mybatis+redis实现二级缓存

Posted 依米欧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot+Mybatis+redis实现二级缓存相关的知识,希望对你有一定的参考价值。

对于查询比较多的项目可以考虑配置二级缓存,mybatis本身的二级缓存是缓存到本地,但是对于多个节点的项目来说,可能会出现数据不一致的问题,所以采用redis缓存,这样二级缓存的数据就可以缓存到内存,可实现多个节点项目的数据同步。

1、配置redis的连接

#redis
gmall.redis.host=172.16.1.250
gmall.redis.port=6379
gmall.redis.pass=Gworld2017
gmall.redis.photo.database=6

#最大分配的对象数  
gmall.redis.maxActive=12000

#最大能够保持idel状态的对象数 
gmall.redis.maxIdle=600

#当池内没有返回对象时,最大等待时间  
gmall.redis.maxWait=2000

gmall.redis.timeout=5000

#当调用borrow Object方法时,是否进行有效性检查  
gmall.redis.testOnBorrow=true

#当调用return Object方法时,是否进行有效性检查  
gmall.redis.testOnReturn=true

gmall.redis.minIdle=5
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
            http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"
    default-lazy-init="false">
    <bean id="jedisConnFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
        primary="true">
        <property name="hostName" value="${gmall.redis.host}" />
        <property name="port" value="${gmall.redis.port}" />
        <property name="password" value="${gmall.redis.pass}" />
        <property name="timeout" value="${gmall.redis.timeout}" />
        <property name="database" value="${gmall.redis.photo.database}" />
    </bean>
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
        primary="true">
        <property name="connectionFactory" ref="jedisConnFactory" />
        <property name="exposeConnection" value="true" />
        <property name="keySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
        </property>
        <property name="hashKeySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="hashValueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
        </property>
    </bean>
</beans>

 

2、配置mybatis-config.xml文件

  

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
           <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

3、编写RedisCache实现Cache类

package com.gcard.gwmedia.cache;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;

import com.gcard.gwmedia.utils.SpringBeanFactoryUtils;

public class RedisCache implements Cache {
    
    Logger logger = LoggerFactory.getLogger(getClass());

    private final String FREFIX = "CACHE_";
    private final String id;
    
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
    
    @SuppressWarnings("rawtypes")
    private RedisTemplate redisTemplate;
    
    private long cleanInterval;
    
    private long lastClear;
    
    public RedisCache(String id){
        if(id == null){
            throw new IllegalArgumentException("Cache instance require an ID");
        }
        this.id = id;
        this.cleanInterval = 1 * 60 * 60 * 1000;//一个小时
        this.lastClear = System.currentTimeMillis();
    }

    @SuppressWarnings({ "unchecked" })
    @Override
    public void clear() {
        lastClear = System.currentTimeMillis();
        String strKey = FREFIX + id.toString();
        getRedisTemplate().delete(strKey);
        logger.debug("Clear all the cached query result from redis");
    }

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

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public Object getObject(Object key) {
        if(key != null){
            String strKey = FREFIX + id.toString();
            if(clearWhenStale(strKey)){
                return null;
            }
            RedisTemplate redisTemplate = getRedisTemplate();
            Object obj = redisTemplate.opsForHash().get(strKey, key.toString());
            logger.debug("Get cached query result from redis");
            if(obj != null){
                return obj;
            }else{
                return null;
            }
        }else{
            return null;
        }
    }

    @SuppressWarnings("rawtypes")
    private RedisTemplate getRedisTemplate() {
        if(redisTemplate == null){
            redisTemplate = (RedisTemplate) SpringBeanFactoryUtils.getBean("redisTemplate");
        }
        return redisTemplate;
    }
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public void putObject(Object key, Object value) {
        if (key != null) {
            String strKey = FREFIX + id.toString();
            clearWhenStale(strKey);
            RedisTemplate redisTemplate = getRedisTemplate();
            redisTemplate.opsForHash().put(strKey,key.toString(),value);
            logger.debug("Put query result to redis");
        }
    }
    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }

    @Override
    public int getSize() {
        return 0;
    }


    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public Object removeObject(Object key) {
        if (key != null) {
            String strKey = FREFIX + id.toString();
            RedisTemplate redisTemplate = getRedisTemplate();
            redisTemplate.opsForHash().delete(strKey, key.toString());
            logger.debug("Remove cached query result from redis");
        }
        return null;
    }
    public boolean clearWhenStale(Object key){
        if(System.currentTimeMillis()-lastClear > cleanInterval){
            logger.info("clearWhenStale key={}", key);
            clear();
            return true;
        }
        return false;
        
    }
}

4、配置mapper.xml文件

在mapper.xml文件加入<cache/>

<cache type="com.gcard.gwmedia.cache.RedisCache"/>

5、Application启动类添加注解@EnableCaching

package com.gcard.gwmedia;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ImportResource;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@ImportResource(locations = {"classpath:/config/applicationContext.xml"})
@EnableAsync
@EnableCaching
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
}

 


以上是关于SpringBoot+Mybatis+redis实现二级缓存的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot整合Redis,一篇解决缓存的所有问题

SpringBoot整合Redis,一篇解决缓存的所有问题

SpringBoot整合Redis,一篇解决缓存的所有问题

SpringBoot整合Redis,一篇解决缓存的所有问题

SpringBoot整合Redis 之 lettuce #私藏项目实操分享#

springboot整合mybatis,redis,代码