mybatis使用redis做二级缓存

来源:互联网 发布:星际战甲软件 编辑:程序博客网 时间:2024/05/22 04:32

1. 介绍

  使用mybatis时可以使用二级缓存提高查询速度,进而改善用户体验。

  使用redis做mybatis的二级缓存可是内存可控<如将单独的服务器部署出来用于二级缓存>,管理方便。

 

2. 使用思路

  2.1 配置redis.xml 设置redis服务连接各参数

  2.1 在配置文件中使用 <setting> 标签,设置开启二级缓存;

  2.2 在mapper.xml 中使用<cache type=”com.demo.RedisCacheClass” /> 将cache映射到指定的RedisCacheClass类中;

  2.3 映射类RedisCacheClass 实现 MyBatis包中的Cache类,并重写其中各方法;

    在重写各方法体中,使用redisFactory和redis服务建立连接,将缓存的数据加载到指定的redis内存中(putObject方法)或将redis服务中的数据从缓存中读取出来(getObject方法);

    在redis服务中写入和加载数据时需要借用spring-data-redis.jar中JdkSerializationRedisSerializer.class中的序列化(serialize)和反序列化方法(deserialize),此为包中封装的redis默认的序列化方法;

  2.4 映射类中的各方法重写完成后即可实现mybatis数据二级缓存到redis服务中;

 

3. 代码实践

  3.1 配置redis.xml

复制代码
<?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:p="http://www.springframework.org/schema/p"    xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:task="http://www.springframework.org/schema/task"    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/mvc    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd    http://www.springframework.org/schema/aop    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd    http://www.springframework.org/schema/tx     http://www.springframework.org/schema/tx/spring-tx.xsd    http://www.springframework.org/schema/context    http://www.springframework.org/schema/context/spring-context-3.0.xsd    http://www.springframework.org/schema/task    http://www.springframework.org/schema/task/spring-task-3.0.xsd" >    <!-- enable autowire -->    <context:annotation-config />     <task:annotation-driven/>    <context:component-scan base-package="demo.util,demo.salesorder,demo.person" />    <!-- Configures the @Controller programming model 必须加上这个,不然请求controller时会出现no mapping url错误-->    <mvc:annotation-driven />    <!-- 引入数据库配置文件 -->    <bean id="propertyConfigurer"    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="locations">            <list>                <value>classpath:sysconfig/jdbc.properties</value>                <value>classpath:sysconfig/redis.properties</value>            </list>        </property>    </bean>    <!-- JDBC -->    <bean id="defaultDataSource"   class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"        p:driverClassName="${jdbc.driverClassName}"        p:url="${jdbc.databaseurl}"        p:username="${jdbc.username}"        p:password="${jdbc.password}" >        <property name="maxActive">            <value>${jdbc.maxActive}</value>        </property>          <property name="initialSize">            <value>${jdbc.initialSize}</value>        </property>          <property name="maxWait">            <value>${jdbc.maxWait}</value>        </property>          <property name="maxIdle">            <value>${jdbc.maxIdle}</value>        </property>        <property name="minIdle">            <value>${jdbc.minIdle}</value>        </property>        <!-- 只要下面两个参数设置成小于8小时(MySql默认),就能避免MySql的8小时自动断开连接问题 -->        <property name="timeBetweenEvictionRunsMillis">            <value>18000000</value>        </property><!-- 5小时 -->        <property name="minEvictableIdleTimeMillis">            <value>10800000</value>        </property><!-- 3小时 -->        <property name="validationQuery">            <value>SELECT 1</value>        </property>        <property name="testOnBorrow">            <value>true</value>        </property>    </bean>    <!-- define the SqlSessionFactory -->    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">        <property name="dataSource" ref="defaultDataSource" />        <property name="typeAliasesPackage" value="demo.salesorder,demo.person" />        <!-- 可以单独指定mybatis的配置文件,或者写在本文件里面。 用下面的自动扫描装配(推荐)或者单独mapper -->         <property name="configLocation" value="classpath:sysconfig/mybatis-config.xml" />    </bean>    <!-- 自动扫描并组装MyBatis的映射文件和接口-->    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">        <property name="basePackage" value="demo.*.data" />        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>    </bean>    <!-- JDBC END -->    <!-- redis数据源 -->    <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>    <!-- Spring-redis连接池管理工厂 -->    <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="password" value="${redis.pass}" />        <property name="timeout" value="${redis.timeout}" />        <property name="poolConfig" ref="poolConfig" />    </bean>          <!-- 使用中间类解决RedisCache.jedisConnectionFactory的静态注入,从而使MyBatis实现第三方缓存 -->    <bean id="redisCacheTransfer" class="demo.redis.RedisCacheTransfer">        <property name="jedisConnectionFactory" ref="jedisConnectionFactory"/>    </bean>          <bean class="demo.util.UTF8StringBeanPostProcessor"></bean>          </beans>    
复制代码

 

  3.2 mybatis.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>    <!-- 配置mybatis的缓存,延迟加载等等一系列属性 -->    <settings>        <!-- 全局映射器启用缓存 *主要将此属性设置完成即可-->        <setting name="cacheEnabled" value="true"/>        <!-- 查询时,关闭关联对象即时加载以提高性能 -->        <setting name="lazyLoadingEnabled" value="false"/>        <!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->        <setting name="multipleResultSetsEnabled" value="true"/>        <!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 -->        <setting name="aggressiveLazyLoading" value="true"/>    </settings></configuration>
复制代码

 

   3.3 在mapper.xml中映射缓存类RedisCacheClass

复制代码
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="demo.person.data.UserMapper"><cache type="demo.redis.cache.RedisCache"/> <!-- *映射语句 --><select id="getPersonList" parameterType="map" resultType="Person">    select *         from person    <where>        1=1        <if test="user_name!=null">            and user_name=#{user_name}        </if>        </where></select><insert id="addPerson" parameterType="Person" keyProperty="id" useGeneratedKeys="true">    insert into person(        login_id,        user_name,        gender,        birthday,        remark    )values(        #{login_id},        #{user_name},        #{gender},        #{birthday},        #{remark}    )</insert></mapper>
复制代码

 

  3.4 实现Mybatis中的Cache接口

    Cache.class源码:

复制代码
/* *    Copyright 2009-2012 the original author or authors. *    http://www.apache.org/licenses/LICENSE-2.0*/package org.apache.ibatis.cache;import java.util.concurrent.locks.ReadWriteLock;public interface Cache {  String getId();  int getSize();  void putObject(Object key, Object value);  Object getObject(Object key);  Object removeObject(Object key);  void clear();  ReadWriteLock getReadWriteLock();}
复制代码

 

    RedisCache.java

复制代码
package demo.redis.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.connection.jedis.JedisConnection;import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;import org.springframework.data.redis.serializer.RedisSerializer;import redis.clients.jedis.exceptions.JedisConnectionException;public class RedisCache implements Cache //实现类{    private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);    private static JedisConnectionFactory jedisConnectionFactory;    private final String id;    /**     * The {@code ReadWriteLock}.     */    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();    public RedisCache(final String id) {        if (id == null) {            throw new IllegalArgumentException("Cache instances require an ID");        }        logger.debug("MybatisRedisCache:id=" + id);        this.id = id;    }    @Override    public void clear()    {        JedisConnection 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;        JedisConnection connection = null;        try        {            connection = jedisConnectionFactory.getConnection();            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); //借用spring_data_redis.jar中的JdkSerializationRedisSerializer.class            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;        JedisConnection 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)    {        JedisConnection connection = null;        try        {            logger.info(">>>>>>>>>>>>>>>>>>>>>>>>putObject:"+key+"="+value);            connection = jedisConnectionFactory.getConnection();            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); //借用spring_data_redis.jar中的JdkSerializationRedisSerializer.class            connection.set(serializer.serialize(key), serializer.serialize(value)); //利用其序列化方法将数据写入redis服务的缓存中        }        catch (JedisConnectionException e)        {            e.printStackTrace();        }        finally        {            if (connection != null) {                connection.close();            }        }    }    @Override    public Object removeObject(Object key)    {        JedisConnection connection = null        Object result = null;        try        {            connection = jedisConnectionFactory.getConnection();            RedisSerializer<Object> 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;    }}
复制代码

 

  4. 总结

    通过重写Cache类中的方法,将mybatis中默认的缓存空间映射到redis空间中。

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 爸妈吵架妈妈走了爸爸哭了该怎么办 总担心旅馆被拍视频传上网怎么办 微博买了猜冠军现在停了怎么办 脸上毛孔大有黑头怎么办小窍门去 进去精神病院出来真的疯了怎么办 房子已过户新业主不交物业费怎么办 村委会欠百姓征地补偿款不给怎么办 因为近亲人人都不看好的婚姻怎么办 碰到工作中特别积极的同事怎么办 丈夫车祸死亡妻子和孩子以后怎么办 丈夫死后妻子改嫁儿子不同意怎么办 满了60岁社保没满15年怎么办 捷豹的dpf灯亮了怎么办 朋友如新直销产品是你该怎么办 传福音接受了却被家人拦阻该怎么办 奶奶出钱由孙子抓奖中奖后怎么办 我不想学车了驾校不同意退学怎么办 2017年大学挂科面临退学怎么办 微信重新登录后东西全没了怎么办 宝宝吃鸡蛋过敏全身起红疹怎么办 180在产蛋鸡因断鸡减产怎么办 住友39熔接机熔接损耗大怎么办 支付宝实名认证刷脸失败怎么办 支付宝注册刷脸不是本人怎么办 小学科学只考88分中学怎么办 收银机关机时才上传数据是怎么办 刚做的系统玩cf卡屏怎么办 办健康证的资料掉了怎么办 刚刚办得的健康证掉了怎么办 房子都过户了银行贷不了款怎么办 我要办大病迁出应该怎么办啊? 遗产继承后户口没地迁出怎么办 安徽蒙城怎么办去韩国的签证的 夜间有人私自收停车费应该怎么办 上次摸不到环尾丝这次摸到了怎么办 法院判决书下来后对方不给钱怎么办 法院判决书下来了钱还保全么怎么办 深圳路边泊车不知道泊车编号怎么办 当事人进拘留所了我的工资怎么办 昆明公租房住满5年后怎么办 昆明公租房房子到期缴纳金怎么办