3-SSM框架整合Redis做MyBatis二级缓存

什么是Redis?
“Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。”
上面的这段对redis的描述来自百度词条。个人理解,redis就是一个键值对类型的数据库,暂时先理解这点就够。至于redis原理实现,那些后续我们慢慢一起探究,我们先从实战的角度来看,SSM框架本身就引入了MyBatis作为架构的持久层,redis整合到ssm框架后要承担什么角色?下面我们从一个实际案例来一起讨论redis整合到ssm框架中的意义:
一个接口日常的访问次数是每日10万次左右,而这个接口主要的功能是从数据库获取用户需要的数据(更新频率较低)拼装成一定格式返回给客户端。这正常流程是:用户请求接口→接口调用数据库查询→数据库返回结果→接口返回响应结果。这样的话对数据库的读取操作就很频繁,对数据库的压力就会很大,这时我们就需要引入缓存。将已经查询到结果交给redis去管理,没有的数据再去数据库读取出来交给redis管理,而新增、更新或删除的依旧交给Mybatis操作,必要的时候刷新redis。当然,这部分的功能很多spring-data-redis都帮我们封装好了,下面我们就自己来实践一遍吧。


Redis安装
使用redis首先要先安装个redis的服务器,可以从https://redis.io/下载,目前redis的最新版本是4.0.6版本。
下载下来的是一个redis-4.0.6.tar.gz的压缩包,解压它得到一个文件夹,里面有17个文件或文件夹。
但这还没完,你可以把这个文件夹拷贝到你想放的位置,然后打开terminal切换到你刚放的文件夹的那个路径下,输入:
make
然后等待即可了,下面熟悉下redis常用的几个指令
1)启动redis
src/redis-server
2)进入命令行客户端
src/redis-cli
3)设置一个键值
redis> set key value
4)获取一个键值
redis> get key
下面我们就将redis服务器打开src/redis-server,继续我们的整合吧。


SSM整合Redis

首先,还是基于上一篇文章最后的成果上进行整合。在pom.xml声明依赖的jar包。


<dependency>
    <groupId>redis.clientsgroupId>
    <artifactId>jedisartifactId>
    <version>2.4.2version>
dependency>
<dependency>
    <groupId>org.springframework.datagroupId>
    <artifactId>spring-data-redisartifactId>
    <version>1.4.0.RELEASEversion>
dependency>

然后在src/main/resources目录下配置redis连接信息redis.properties。

redis.host={redis服务器地址}
redis.port={redis服务器端口号}
redis.maxIdle=2000
redis.maxActive=60000
redis.maxWait=1000
redis.testOnBorrow=true
redis.timeout=100000
redis.password={redis服务器密码}
defaultCacheExpireTime=60

接着在spring-context.xml中添加redis的配置,但是这边会用到2个类,用来解决RedisCache.jedisConnectionFactory静态注入的问题,这里先实现下,建议在原本的目录结构下新建个utils的package存放这类文件。

public class RedisCache implements Cache {
    private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
    private static JedisConnectionFactory jedisConnectionFactory;
    private final String id;
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    public RedisCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("require an ID");
        }
        logger.debug("RedisCache:id=" + id);
        this.id = id;
    }
    @Override
    public void clear() {
        RedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            connection.flushDb();
            connection.flushAll();
        } catch (JedisConnectionException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }
    @Override
    public String getId() {
        return this.id;
    }
    @Override
    public Object getObject(Object key) {
        Object result = null;
        RedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            RedisSerializer serializer = new JdkSerializationRedisSerializer();
            result = serializer.deserialize(connection.get(serializer.serialize(key)));
        } catch (JedisConnectionException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        return result;
    }
    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }
    @Override
    public int getSize() {
        int result = 0;
        RedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            result = Integer.valueOf(connection.dbSize().toString());
        } catch (JedisConnectionException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        return result;
    }
    @Override
    public void putObject(Object key, Object value) {
        RedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            RedisSerializer serializer = new JdkSerializationRedisSerializer();
            connection.set(serializer.serialize(key), serializer.serialize(value));
        } catch (JedisConnectionException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }
    @Override
    public Object removeObject(Object key) {
        RedisConnection connection = null;
        Object result = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            RedisSerializer serializer = new JdkSerializationRedisSerializer();
            result = connection.expire(serializer.serialize(key), 0);
        } catch (JedisConnectionException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        return result;
    }
    public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
        RedisCache.jedisConnectionFactory = jedisConnectionFactory;
    }
}

public class RedisCacheTransfer {
    @Autowired
    public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
        RedisCache.setJedisConnectionFactory(jedisConnectionFactory);
    }
}

然后,在spring-context.xml中添加redis的配置。


    <context:property-placeholder location="classpath*:/redis.properties" ignore-unresolvable="true"  />
    
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">  
        
        <property name="maxIdle" value="${redis.maxIdle}" />  
        
        <property name="maxTotal" value="${redis.maxActive}" />  
        
        <property name="maxWaitMillis" value="${redis.maxWait}" />  
        
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />  
    bean>
    
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        
        <property name="hostName" value="${redis.host}" />
        
        <property name="port" value="${redis.port}" />
        
        <property name="timeout" value="${redis.timeout}" />
        <property name="poolConfig" ref="poolConfig" />
    bean> 
    
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <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="enableTransactionSupport" value="true">property>
    bean>
    
    <bean id="redisCacheTransfer" class="com.maven4web.utils.RedisCacheTransfer">
        <property name="jedisConnectionFactory" ref="jedisConnectionFactory"/>
    bean> 

    
    <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
        <constructor-arg index="0" ref="redisTemplate" />
    bean>

然后在mybatis-config.xml中开启mybatis的全局缓存,配置相关参数。



<configuration>
    <settings>
        
        <setting name="logImpl" value="STDOUT_LOGGING" />
        
        <setting name="cacheEnabled" value="true" />
        
        <setting name="lazyLoadingEnabled" value="false"/> 
        
        <setting name="multipleResultSetsEnabled" value="true"/>
        
        <setting name="aggressiveLazyLoading" value="true"/>
    settings>
    
    <typeAliases>
    typeAliases>
configuration>

其次,拿上次的TestMapper.xml做测试,需在其中添加配置。


<cache type="com.maven4web.utils.RedisCache" />

接着修改下我们的TestController的方法吧。

@Controller
public class TestController {
    @Autowired
    private TestService testService;
    @RequestMapping("/test.action")
    @ResponseBody
    public List test(){
        List tests = testService.getAll();
        return tests;
    }
}

部署下项目,启动tomcat看看效果,可选结果就让人失望的,redis根本没有缓存数据,还是去数据库取数据了。
3-SSM框架整合Redis做MyBatis二级缓存_第1张图片
那问题出在哪里呢?回顾下redis是什么?键值型的数据库,但貌似我们的实体没有序列化,无法满足使用的要求,那就改造下我们的实体Test。

public class Test implements Serializable{
    private static final long serialVersionUID = -5366358304131939882L;
    private Integer id;
    private String username;
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
}

ok,现在再次启动服务试试效果,可以看到执行两次接口的情况不一样了,第一次缓存没有数据去查询了一次数据库,第一次直接从缓存获取数据,没查数据库了。
3-SSM框架整合Redis做MyBatis二级缓存_第2张图片

你可能感兴趣的:(架构)