1、实现 mybatis 的二级缓存,一般来说有如下两种方式:

1) 采用 mybatis 内置的 cache 机制。
2) 采用三方 cache 框架, 比如ehcache, oscache 等等.

2、导入依赖:

   <!-- redis与spring的整合依赖 -->
    <redis.version>2.9.0</redis.version>
    <redis.spring.version>1.7.1.RELEASE</redis.spring.version>
    
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>${redis.version}</version>
    </dependency>
    <dependency>
      <groupId>org.spring work.data</groupId>
      <artifactId>spring-data-redis</artifactId>
      <version>${redis.spring.version}</version>
    </dependency>

3、 log4j2配置:Log4j2 + Slf4j

上一篇博客有:https://mp.csdn.net/mdeditor/85159453#

4、jackson依赖:

<!-- jackson -->
    <jackson.version>2.9.3</jackson.version> 

<!-- jackson -->
    <dependency>
      <groupId>com.faster .jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.faster .jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.faster .jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>${jackson.version}</version>
    </dependency>

5、spring + redis 集成实现缓存功能(与mybatis无关)

5-1: 添加两个redis的配置文件,并将redis.properties和applicationContext-redis. l配置到applicationContext. 文件中

redis.properties文件放到Resources目录下

redis.hostName=192.168.147.142
redis.port=6379
redis.password=123456
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true

applicationContext-redis. 文件
<?  version=\"1.0\" encoding=\"UTF-8\"?>
<beans  ns=\"http://www.spring work.org/schema/beans\"
        ns:xsi=\"http://www.w3.org/2001/ Schema-instance\"
        ns:context=\"http://www.spring work.org/schema/context\"
       xsi:schemaLocation=\"http://www.spring work.org/schema/beans http://www.spring work.org/schema/beans/spring-beans.xsd http://www.spring work.org/schema/context http://www.spring work.org/schema/context/spring-context.xsd\">

    <!-- 1. 引入properties配置文件 -->
    <!--<context:property-placeholder location=\"classpath:redis.properties\" />-->

    <!-- 2. redis连接池配置-->
    <bean id=\"poolConfig\" class=\"redis.clients.jedis.JedisPoolConfig\">
        <!--最大空闲数-->
        <property name=\"maxIdle\" value=\"${redis.maxIdle}\"/>
        <!--连接池的最大数据库连接数  -->
        <property name=\"maxTotal\" value=\"${redis.maxTotal}\"/>
        <!--最大建立连接等待时间-->
        <property name=\"maxWaitMillis\" value=\"${redis.maxWaitMillis}\"/>
        <!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟)-->
        <property name=\"minEvictableIdleTimeMillis\" value=\"${redis.minEvictableIdleTimeMillis}\"/>
        <!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3-->
        <property name=\"numTestsPerEvictionRun\" value=\"${redis.numTestsPerEvictionRun}\"/>
        <!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1-->
        <property name=\"timeBetweenEvictionRunsMillis\" value=\"${redis.timeBetweenEvictionRunsMillis}\"/>
        <!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个-->
        <property name=\"testOnBorrow\" value=\"${redis.testOnBorrow}\"/>
        <!--在空闲时检查有效性, 默认false  -->
        <property name=\"testWhileIdle\" value=\"${redis.testWhileIdle}\"/>
    </bean>

    <!-- 3. redis连接工厂 -->
    <bean id=\"connectionFactory\" class=\"org.spring work.data.redis.connection.jedis.JedisConnectionFactory\"
          destroy-method=\"destroy\">
        <property name=\"poolConfig\" ref=\"poolConfig\"/>
        <!--IP地址 -->
        <property name=\"hostName\" value=\"${redis.hostName}\"/>
        <!--端口号  -->
        <property name=\"port\" value=\"${redis.port}\"/>
        <!--如果Redis设置有密码  -->
        <property name=\"password\" value=\"${redis.password}\"/>
        <!--客户端超时时间单位是毫秒  -->
        <property name=\"timeout\" value=\"${redis.timeout}\"/>
    </bean>

    <!-- 4. redis操作模板,使用该对象可以操作redis  -->
    <bean id=\"redisTemplate\" class=\"org.spring work.data.redis.core.RedisTemplate\">
        <property name=\"connectionFactory\" ref=\"connectionFactory\"/>
        <!--如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can\'t cast to String!!  -->
        <property name=\"keySerializer\">
            <bean class=\"org.spring work.data.redis.serializer.StringRedisSerializer\"/>
        </property>
        <property name=\"valueSerializer\">
            <bean class=\"org.spring work.data.redis.serializer.GenericJackson2JsonRedisSerializer\"/>
        </property>
        <property name=\"hashKeySerializer\">
            <bean class=\"org.spring work.data.redis.serializer.StringRedisSerializer\"/>
        </property>
        <property name=\"hashValueSerializer\">
            <bean class=\"org.spring work.data.redis.serializer.GenericJackson2JsonRedisSerializer\"/>
        </property>
        <!--开启事务  -->
        <property name=\"enableTransactionSupport\" value=\"true\"/>
    </bean>

    <!-- 5.使用中间类解决RedisCache.RedisTemplate的静态注入,从而使MyBatis实现第三方缓存 -->
    <bean id=\"redisCacheTransfer\" class=\"com.zking.ssm.book.util.RedisCacheTransfer\">
        <property name=\"redisTemplate\" ref=\"redisTemplate\"/>
    </bean>
</beans>

注:

spring中引入第二个属性文件会出现“找不到某个配置项”错误,这是因为spring只允许有一个<context:property-placeholder/>    

  <!--引入一个属性文件的写法-->      
  <context:property-placeholder ignore-unresolvable=\"true\" location=\"classpath:jdbc.properties\" />

  <!--引入两个或多个属性文件的写法-->
  <context:property-placeholder ignore-unresolvable=\"true\" location=\"classpath:jdbc.properties,classpath:redis.properties\" />

注2:通过import标签将spring-redis. 导入到applicationContext. 文件中

       <!--导入redis配置-->
       <import resource=\"applicationContext-redis. \"/>
applicationContext. 文件中:

\"在这里插入图片描述\"

6、 将redis缓存引入到mybatis中

6-1: 创建mybatis的自定义缓存类“RedisCache”,必须实现org.apache.ibatis.cache.Cache接口

RedisCache.java:

package com.zking.ssm.redis;


import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spring work.dao.DataAccessException;
import org.spring work.data.redis.connection.RedisConnection;
import org.spring work.data.redis.core.RedisCallback;
import org.spring work.data.redis.core.RedisTemplate;

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


public class RedisCache implements Cache //实现类
{
    private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);

    private static RedisTemplate<String, > redisTemplate;

    private final String id;

    /**
     * The {@code ReadWriteLock}.
     */
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    @Override
    public ReadWriteLock getReadWriteLock()
    {
        return this.readWriteLock;
    }

    public static void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisCache.redisTemplate = redisTemplate;
    }

    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 String getId() {
        return this.id;
    }

    @Override
    public void put (  key,   value) {
        try{
            logger.info(\">>>>>>>>>>>>>>>>>>>>>>>>put : key=\"+key+\",value=\"+value);
            if(null!=value)
                redisTemplate.opsForValue().set(key.toString(),value,2, TimeUnit.DAYS);
        }catch (Exception e){
            e.printStackTrace();
            logger.error(\"redis保存数据异常!\");
        }
    }

    @Override
    public   get (  key) {
        try{
            logger.info(\">>>>>>>>>>>>>>>>>>>>>>>>get : key=\"+key);
            if(null!=key)
                return redisTemplate.opsForValue().get(key.toString());
        }catch (Exception e){
            e.printStackTrace();
            logger.error(\"redis获取数据异常!\");
        }
        return null;
    }

    @Override
    public   remove (  key) {
        try{
            if(null!=key)
                return redisTemplate.expire(key.toString(),1,TimeUnit.DAYS);
        }catch (Exception e){
            e.printStackTrace();
            logger.error(\"redis获取数据异常!\");
        }
        return null;
    }

    @Override
    public void clear() {
        Long size=redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
                Long size = redisConnection.dbSize();
                //连接清除数据
                redisConnection.flushDb();
                redisConnection.flushAll();
                return size;
            }
        });
        logger.info(\">>>>>>>>>>>>>>>>>>>>>>>>clear: 清除了\" + size + \"个对象\");
    }

    @Override
    public int getSize() {
        Long size = redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                return connection.dbSize();
            }
        });
        return size.intValue();
    }
}

6-2:静态注入中间类“RedisCacheTransfer”,解决RedisCache中RedisTemplate的静态注入,从而使MyBatis实现第三方缓存 RedisCacheTransfer.java:
package com.zking.ssm.book.util;

import org.spring work.beans.factory.annotation.Autowired;
import org.spring work.data.redis.core.RedisTemplate;

public class RedisCacheTransfer {
    @Autowired
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisCache.setRedisTemplate(redisTemplate);
    }
}

6-3:spring与mybatis整合文件中开发二级缓存
6-4: 在XxxMapper. 中添加自定义cache功能,示例:
  <cache type=\"com.zking.ssm.util.RedisCache\"></cache>

注:

type:指定redis的二级缓存类的全路径名
eviction:二级缓存算法(FIFO/LRU/SOFT/WEAK)
flushInterval:刷新间隔,间隔多长时间清空缓存,被动触发非定时器轮询
size:缓存大小。每个缓存可以存储 1024 个列表或对象的引用
readOnly:缓存将作为“读/写”缓存,意味着获取的对象不是共享的且对调用者是安全的。不会有其它的调用者或线程潜在修改。
 <cache
 	type=\"com.zking.zf.redis.RedisCache\"
	eviction=\"LRU\"
	flushInterval=\"6000000\"
	size=\"1024\"
	readOnly=\"false\"
	/>

注意: pom对properties文件的加载!!!

\"在这里插入图片描述\"

注意点:

spring上下文,不允许两处及以上的文件注册,需要使用多文件注册的方法
pom. 中记得将redis.properties文件给包含进去
spring-context.

附加:

MyBatis内置的二级缓存算法
Mybatis的所有Cache算法都是基于装饰器模式对PerpetualCache扩展增加功能。
1)

FIFO:先入先出,基于 edList实现;

2)LRU:最近最少使用,基于 edHashMap实现,在put的时候,自动移除最少使用缓存对象;
3)

SOFT:对Cache的value进行SoftReference包装;当缓存对象是Soft reference可达时,gc会向系统申请更多内存,而不是直接回收它,当内存不足的时候才回收它;

4)WEAK:对Cache的value进行WeakReference包装;WeakReference不会强制对象保存在内存中。它拥有比较短暂的生命周期,允许你使用垃圾回收器的能力去权衡一个对象的可达性。在垃圾回收器扫描它所管辖的内存区域过程中,一旦gc发现对象是weakReference可达,就会把它放到ReferenceQueue中,等下次gc时回收它。

收藏 打印