Mybatis使用Redis做二级缓存

由于Redis是非关系型数据库,数据是储存到内存中的,而从内存中读取数据要比从硬盘中读取数据的速度要快很多,并且redis可以持久性化数据,所以可以用redis做数据的缓存。

首先导入jar包:spring-data-redis.jar

配置文件:

redis.host=192.168.81.128
redis.port=6379
redis.pass=redis
redis.maxIdle=300
redis.timeout=5000
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true

配置Spring.xml:

    <!-- spring集成redis -->
    <bean id="config" 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="connectionFactory" 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="config"/>
      </bean>

    <!--  <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
     </bean> -->

     <bean id="redisUtil" class="com.chinaedu.back.util.RedisUtil">
        <property name="jedisConnectionFactory" ref="connectionFactory"/>
     </bean>

     <bean id="redisCacheTransfer" class="com.chinaedu.back.util.RedisCacheTransfer">
        <property name="connectionFactory" ref="connectionFactory"/>
     </bean>

配置完之后你可以测试一下是否能够连接上redis:
测试代码:

    @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:spring.xml")
public class TestRedis {

    @Autowired
    private JedisConnectionFactory connectionFactory;

    @Test
    public void testSetValue(){
        RedisConnection connection = connectionFactory.getConnection();
        Jedis jedis= connectionFactory.getShardInfo().createResource();
        jedis.set("name","小明");
    }
    @Test
    public void testGetValue(){
        RedisConnection connection = connectionFactory.getConnection();
        Jedis jedis= connectionFactory.getShardInfo().createResource();
        String name = jedis.get("name");
        System.out.println(name);
    }
}

如果测试成功则进行下面的步骤:
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"/>

        <!-- 允许使用列标签代替列名 -->
        <setting name="useColumnLabel" value="true"/>

        <!-- 不允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->
        <setting name="useGeneratedKeys" value="false"/>

        <!-- 给予被嵌套的resultMap以字段-属性的映射支持 FULL,PARTIAL -->
        <setting name="autoMappingBehavior" value="PARTIAL"/>

        <!-- 对于批量更新操作缓存SQL以提高性能 BATCH,SIMPLE -->
        <!-- <setting name="defaultExecutorType" value="BATCH" /> -->

        <!-- 数据库超过25000秒仍未响应则超时 -->
        <!-- <setting name="defaultStatementTimeout" value="25000" /> -->

        <!-- Allows using RowBounds on nested statements -->
        <setting name="safeRowBoundsEnabled" value="false"/>

        <!-- Enables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn. -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!-- MyBatis uses local cache to prevent circular references and speed up repeated nested queries. By default (SESSION) all queries executed during a session are cached. If localCacheScope=STATEMENT 
            local session will be used just for statement execution, no data will be shared between two different calls to the same SqlSession. -->
        <setting name="localCacheScope" value="SESSION"/>

        <!-- Specifies the JDBC type for null values when no specific JDBC type was provided for the parameter. Some drivers require specifying the column JDBC type but others work with generic values 
            like NULL, VARCHAR or OTHER. -->
        <setting name="jdbcTypeForNull" value="OTHER"/>

        <!-- Specifies which Object's methods trigger a lazy load -->
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>

        <!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 -->
        <setting name="aggressiveLazyLoading" value="true"/>

    </settings>

</configuration>

mapper.xml:

<?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="com.chinaedu.back.dao.UserDao">

//自定义的cache
<cache  type="com.chinaedu.back.cache.RedisCache" />

    <!-- <insert id="addadminrole"> insert into sys_admin_role(admin_id,role_id) 
        values(#{admin_id},#{role_id}) </insert> -->

    <sql id="usersql">
        select f_user_id userId, f_real_name realName,f_role_id
        roleId,f_name name,f_pwd pwd,f_eamil email,f_phone phone,f_state state
        from t_user
    </sql>

    <select id="queryByCase" resultType="User">
        <include refid="usersql"></include>
        <where>
            <if test="userId != null">
                f_user_id = #{userId}
            </if>
            <if test="name != null">
                and f_name = #{name}
            </if>
        </where>
    </select>
</mapper>   

实现cache接口:

package com.chinaedu.back.cache;

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

import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.connection.RedisConnection;
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;

/**
 * 自定义cache
 * 
 * @author Administrator
 *
 */
public class RedisCache implements Cache {

    private static JedisConnectionFactory connectionFactory;

    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");
        }
        this.id = id;
    }

    @Override
    public String getId() {
        // TODO Auto-generated method stub
        return this.id;
    }

    @Override
    public void putObject(Object key, Object value) {
        // TODO Auto-generated method stub
        RedisConnection connection = null;
        try {
            connection = connectionFactory.getConnection();
            RedisSerializer<Object> redisSerializer = new JdkSerializationRedisSerializer(); // 借用spring_data_redis.jar中的JdkSerializationRedisSerializer.class
            connection.set(redisSerializer.serialize(key),
                    redisSerializer.serialize(value));// 利用其序列化方法将数据写入redis服务的缓存中
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    @Override
    public Object getObject(Object key) {
        // TODO Auto-generated method stub
        Object result = null;
        RedisConnection connection = null;
        try {
            connection = connectionFactory.getConnection();
            RedisSerializer<Object> 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 Object removeObject(Object key) {
        // TODO Auto-generated method stub
        RedisConnection connection = null;
        System.out.println("key:" + key);
        Object result = null;
        try {
            connection = connectionFactory.getConnection();
            RedisSerializer<Object> redisSerializer = new JdkSerializationRedisSerializer(); // 借用spring_data_redis.jar中的JdkSerializationRedisSerializer.class
            result = connection.expire(redisSerializer.serialize(key), 0);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        return result;
    }

    @Override
    public void clear() {
        // TODO Auto-generated method stub
        RedisConnection connection = null;
        try {
            connection = connectionFactory.getConnection();
            connection.flushDb();
            connection.flushAll();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    @Override
    public int getSize() {
        // TODO Auto-generated method stub
        RedisConnection connection = null;
        int size = 0;
        try {
            connection = connectionFactory.getConnection();
            size = Integer.parseInt(connection.dbSize().toString());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close();
            }
        }

        return size;
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        // TODO Auto-generated method stub
        return this.readWriteLock;
    }

    public static void setConnectionFactory(
            JedisConnectionFactory jedisConnectionFactory) {
        RedisCache.connectionFactory = jedisConnectionFactory;
    }

}

接下来就是测试了:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:spring.xml")
public class TestRedisCache {

    @Autowired
    private UserService userService;

    @Test
    public void query(){
        User user = new User();
        user.setUserId(1);
        long start= System.currentTimeMillis();  
        System.out.println(start);// new Date()为获取当前系统时间
        List<User> queryByCase = userService.queryByCase(user);
        long end= System.currentTimeMillis();  
        System.out.println(end);// new Date()为获取当前系统时间
        for (User user2 : queryByCase) {
            System.out.println(user2);
        }
        System.out.println(end-start);
    }
    @Test
    public void delete(){
        userService.delete(2);
    }
}

日志调成debug级别
第一次查询的时候会有sql语句打印出来
第二次则没有

然后再通过redis的客户端查询,命令为:
keys *:结果为:
127.0.0.1:6379> keys *
1) “\xac\xed\x00\x05sr\x00 org.apache.ibatis.cache.CacheKey\x0f\xe9\xd5\xb4\xcd3\xa8\x82\x02\x00\x05J\x00\bchecksumI\x00\x05countI\x00\bhashcodeI\x00\nmultiplierL\x00\nupdateListt\x00\x10Ljava/util/List;xp\x00\x00\x00\x004\xdb{X\x00\x00\x00\x05s\xe8{J\x00\x00\x00%sr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x05w\x04\x00\x00\x00\x05t\x00)com.chinaedu.back.dao.UserDao.queryByCasesr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x00\x00sq\x00~\x00\x06\x7f\xff\xff\xfft\x00\xa8select f_user_id userId, f_real_name realName,f_role_id\n\t\troleId,f_name name,f_pwd pwd,f_eamil email,f_phone phone,f_state state\n\t\tfrom t_user\n\t \n\t\t WHERE f_user_id = ?sq\x00~\x00\x06\x00\x00\x00\x01x”

 

转自:http://blog.csdn.net/CSDN3436/article/details/69951935

小站主要是个人在开发过程中遇到的问题,解决方案的记录,与君分享。
vsalw技术博客 » Mybatis使用Redis做二级缓存

提供最优质的资源集合

立即查看 了解详情