Mybatis实现二级缓存

目录

一、Mybatis实现Ehcache作为二级缓存

 1、导入相关依赖

2 、修改日志配置,因为ehcache使用了Slf4j作为日志输出

   3、 在Resource中添加一个ehcache.xml的配置文件

4、 在applicationContext.xml中加入chache配置

 5 、mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存

   ①、 开启mybatis的二级缓存

②、 BookMapper.xml中添加二级缓存核心类

 ③、二级缓存使用成功,查询语句只出现一次

④、mybatis框架默认缓存多条数据:

二、Mybatis实现redis作为二级缓存

1. redis常用类

2. 添加jar依赖

  2.1 添加redis相关依赖(pom.xml)

  2.2 log4j2配置

  2.3 jackson(pom.xml中配置)

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

  3.1 添加两个redis的配置文件,并将redis.properties和applicationContext-redis.xml配置到applicationContext.xml文件中

redis.properties

applicationContext-redis.xml(数据源用到JedisPoolConfig)

3.2 将redis缓存引入到mybatis中

将redis配置到BookMapper.xml中

3.2 静态注入中间类“RedisCacheTransfer”,解决RedisCache中RedisTemplate的静态注入,从而使MyBatis实现第三方缓存

 RedisCacheTransfer.java

 加入spring(applicationContext.xml)中进行管理

4、测试


一、Mybatis实现Ehcache作为二级缓存

1. 为什么需要缓存

   拉高程序的性能

2. 什么样的数据需要缓存

   很少被修改或根本不改的数据

   业务场景比如:耗时较高的统计分析sql、电话账单查询sql等

3. ehcache是什么

   Ehcache 是现在最流行的纯Java开源缓存框架,配置简单、结构清晰、功能强大

   注1:本章介绍的是2.X版本,3.x的版本和2.x的版本API差异比较大

4. ehcache的特点

  4.1 够快

      Ehcache的发行有一段时长了,经过几年的努力和不计其数的性能测试,Ehcache终被设计于large, high concurrency systems.

  4.2 够简单

      开发者提供的接口非常简单明了,从Ehcache的搭建到运用运行仅仅需要的是你宝贵的几分钟。其实很多开发者都不知道自己用在用Ehcache,Ehcache被广泛的运用于其他的开源项目

  4.3 够袖珍

      关于这点的特性,官方给了一个很可爱的名字small foot print ,一般Ehcache的发布版本不会到2M,V 2.2.3 才 668KB。

  4.4 够轻量

      核心程序仅仅依赖slf4j这一个包,没有之一!

  4.5 好扩展

      Ehcache提供了对大数据的内存和硬盘的存储,最近版本允许多实例、保存对象高灵活性、提供LRU、LFU、FIFO淘汰算法,基础属性支持热配置、支持的插件多

  4.6 监听器

      缓存管理器监听器 (CacheManagerListener)和 缓存监听器(CacheEvenListener),做一些统计或数据一致性广播挺好用的

  4.7 分布式缓存

      从Ehcache 1.2开始,支持高性能的分布式缓存,兼具灵活性和扩展性

3. ehcache的使用

  3.1 导入相关依赖

  3.2 核心接口

      CacheManager:缓存管理器

      Cache:缓存对象,缓存管理器内可以放置若干cache,存放数据的实质,所有cache都实现了Ehcache接口

      Element:单条缓存数据的组成单位

Mybatis实现二级缓存_第1张图片

 1、导入相关依赖

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-context-supportartifactId>
    <version>${spring.version}version>
dependency>


<dependency>
    <groupId>org.mybatis.cachesgroupId>
    <artifactId>mybatis-ehcacheartifactId>
    <version>1.1.0version>
dependency>


<dependency>
    <groupId>net.sf.ehcachegroupId>
    <artifactId>ehcacheartifactId>
    <version>2.10.0version>
dependency>

2 、修改日志配置,因为ehcache使用了Slf4j作为日志输出

      日志我们使用slf4j,并用log4j来实现。SLF4J不同于其他日志类库,与其它有很大的不同。

       SLF4J(Simple logging Facade for Java)不是一个真正的日志实现,而是一个抽象层( abstraction layer),

       它允许你在后台使用任意一个日志类库。

slf4j是一个抽象日志框架,它的好处在于:它没有具体的实现,谁来实现,取决于框架自身

①、替换成log4j2日志配置相关依赖

    2.9.1

    3.2.0

    1.7.13

Mybatis实现二级缓存_第2张图片

②、 替换成log4j2日志相关依赖


    
    
    
      org.slf4j
      slf4j-api
      ${slf4j.version}
    
    
      org.slf4j
      jcl-over-slf4j
      ${slf4j.version}
      runtime
    

    
    
      org.apache.logging.log4j
      log4j-api
      ${log4j2.version}
    
    
      org.apache.logging.log4j
      log4j-core
      ${log4j2.version}
    
    
    
      org.apache.logging.log4j
      log4j-slf4j-impl
      ${log4j2.version}
    
    
    
      org.apache.logging.log4j
      log4j-web
      ${log4j2.version}
      runtime
    

    
    
      com.lmax
      disruptor
      ${log4j2.disruptor.version}
    

Mybatis实现二级缓存_第3张图片

   3、 在Resource中添加一个ehcache.xml的配置文件



    
    
    
    

    
    
    
    
    
    
    
    
    
    
    
    

    
    
    
    

4、 在applicationContext.xml中加入chache配置

①、复制applicationContext-mybatis.xml创建applicationContext.xml文件

把applicationContext.xml作为spring文件的总路口



    
    


②、创建applicationContext-ehcache.xml

里面存放ehcache.xml的缓存配置,这样ehcache就交给sparing进行管理了



    
    
        
        
    
    
    
        
    

 5 、mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存

   ①、 开启mybatis的二级缓存

applicationContext-mybatis.xml中添加


    
        
        true
        
        false
        
        true
    

Mybatis实现二级缓存_第4张图片

②、 BookMapper.xml中添加二级缓存核心类

Mybatis实现二级缓存_第5张图片

 ③、二级缓存使用成功,查询语句只出现一次

Mybatis实现二级缓存_第6张图片

④、mybatis框架默认缓存多条数据:

可以通过select标签的useCache属性打开或关闭二级缓存

注意有三:

  1. mybatis默认使用的二级缓存框架就是ehcache(org.mybatis.caches.ehcache.EhcacheCache),无缝结合
  2. Mybatis缓存开关一旦开启,可缓存单条记录,也可缓存多条,hibernate不能缓存多条。
  3. Mapper接口上的所有方法上另外提供关闭缓存的属性

5. 小结

  对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,

实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

第二次直接访问缓存:

Mybatis实现二级缓存_第7张图片

不允许查询多条数据进二级缓存,因为会降低性能

useCache="false"

二、Mybatis实现redis作为二级缓存

 

1. redis常用类

  1.1 Jedis

      jedis就是集成了redis的一些命令操作,封装了redis的java客户端

  1.2 JedisPoolConfig

      Redis连接池

  1.3 ShardedJedis

      基于一致性哈希算法实现的分布式Redis集群客户端

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

   1) 采用 mybatis 内置的 cache 机制。

   2) 采用三方 cache 框架, 比如ehcache, oscache 等等.

2. 添加jar依赖

  2.1 添加redis相关依赖(pom.xml)

 

    2.9.0

    1.7.1.RELEASE

    

    

      redis.clients

      jedis

      ${redis.version}

    

    

      org.springframework.data

      spring-data-redis

      ${redis.spring.version}

    

 版本冲突问题:

      1. ClassNotFoundException  : redis/client/util/geoUtils    说这个类找不到。

      2. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisTemplate' defined in class path resource [applicationContext.xml]

         说创建 redisTemplate bean 对象时失败了。

      redis.client 2.9.0 ---- spring-data-redis  1.7.1.RELEASE

      redis.client 2.9.0 ---- spring-data-redis  1.7.2.RELEASE    这两个是可以使用的

  2.2 log4j2配置

  2.3 jackson(pom.xml中配置)

    2.9.3

    

      com.fasterxml.jackson.core

      jackson-databind

      ${jackson.version}

    

    

      com.fasterxml.jackson.core

      jackson-core

      ${jackson.version}

    

    

      com.fasterxml.jackson.core

      jackson-annotations

      ${jackson.version}

    

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

  3.1 添加两个redis的配置文件,并将redis.properties和applicationContext-redis.xml配置到applicationContext.xml文件中

      redis.properties

      applicationContext-redis.xml

      注1:将redis.properties导入到applicationContext.xml文件中

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

            

      

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

           

           

redis.properties

我的虚拟机的端口号:192.168.42.138

redis.hostName=192.168.42.138
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.xml(数据源用到JedisPoolConfig



        
        

        
        
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
        

        
        
            
            
            
            
            
            
            
            
            
        

        
        
            
            
            
                
            
            
                
            
            
                
            
            
                
            
            
            
        

        
        
            
        

3.2 将redis缓存引入到mybatis中

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

RedisCache :默认类中没有值,需要借助下面第三方(RedisCacheTransfer中的setRedisTemplate)获得值,而这个RedisCacheTransfer靠 applicationContext-redis.xml中的配置获得·

package com.mwy.util;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.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 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 putObject(Object key, Object value) {
        try{
            logger.info(">>>>>>>>>>>>>>>>>>>>>>>>putObject: key="+key+",value="+value);
            if(null!=value)
                redisTemplate.opsForValue().set(key.toString(),value,60, TimeUnit.SECONDS);
        }catch (Exception e){
            e.printStackTrace();
            logger.error("redis保存数据异常!");
        }
    }
    @Override
    public Object getObject(Object key) {
        try{
            logger.info(">>>>>>>>>>>>>>>>>>>>>>>>getObject: key="+key);
            if(null!=key)
                return redisTemplate.opsForValue().get(key.toString());
        }catch (Exception e){
            e.printStackTrace();
            logger.error("redis获取数据异常!");
        }
        return null;
    }
    @Override
    public Object removeObject(Object 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() {
            @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() {
            @Override
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                return connection.dbSize();
            }
        });
        return size.intValue();
    }
}

将redis配置到BookMapper.xml中

3.2 静态注入中间类“RedisCacheTransfer”,解决RedisCache中RedisTemplate的静态注入,从而使MyBatis实现第三方缓存

 RedisCache 里面使用了redisTemplate, 但是redisTemplate里面没有值使用第三方让redisTemplate 有值:

 RedisCacheTransfer.java

package com.mwy.util;

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

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

 applicationContext-redis.xml:

 加入spring(applicationContext.xml)中进行管理

一个spring文件中只允许使用一个这样的context:property-placeholder标签

注释掉 applicationContext-mybatis.xml::

 在applicationContext.xml中集中配置:










记得查看pom.xml中:

Mybatis实现二级缓存_第8张图片

4、测试

①、记得查看是否正确: 

Mybatis实现二级缓存_第9张图片

②、测试结果

Mybatis实现二级缓存_第10张图片

 同样默认缓存多条数据,阻止也是一样的;

useCache="false" 

Mybatis实现二级缓存_第11张图片

 所以说redis与ehcache使用并没有什么区别,就是配置不同而已

结束!!!

你可能感兴趣的:(java,intellij-idea,spring)