美文网首页程序员
Mybatis (四) 缓存机制

Mybatis (四) 缓存机制

作者: 其实我很菜啊 | 来源:发表于2017-12-10 16:25 被阅读0次

许多运用程序为了提高性能而增加缓存,特别是从数据库中获取的数据,如果缓存中没有,就到表中去查询,表查询的数据添加到缓存中去,下次查询是直接从缓存中读取,Mybatis 包含一个非常强大的查询缓存特性,它可以非常方便的配置和定制,缓存可以极大的提升查询效率。就如同第一次访问某网站时耗时会就一下感觉到卡,关闭网页再访问相同网页时就流畅了很多,所以缓存机制是很重要的。

一、mybatis 的一级缓存

在默认情况下,mybatis 的一级缓存是默认开启的,类似与hiberante,所谓一级缓存也就是基于一个 sqlsession 的查询语句, 即 session 级别的缓存,非全局缓存或者称为非二级缓存。
一级缓存(local cache),即本地缓存,作用域默认为 sqlsession ,当 Session close 后,该 session 中所有 Cache 将被清空,本地缓存不能被关闭,但可以调用 clearCache() 来清空本地缓存。

  • 一级缓存失效的四种情况:
  1. 不同 SqlSession 对应不同的一级缓存
  2. 同一个 SqlSession 但是查询条件不同
  3. 同一个 SqlSession 两次查询期间执行了任何一次增删改的操作
  4. 同一个 SqlSession 两次查询手动清空了缓存

UserMapping.xml

<resultMap type="cn.softjx.modle.User" id="UserMap">
        <result column="t_id" property="id"/>
        <result column="t_username" property="username"/>
        <result column="t_password" property="password"/>
        <result column="t_sid" property="sid"/>
    </resultMap>

   <select id="selectAll2" resultMap="UserMap" >
        select t_id,t_username,t_password from t_user;
    </select>

映射文件不做任何处理,mybatis默认一级缓存
Test.java

@Test
    public void testSelect(){
        try {                   
            List<User> user=mapper.selectAll2();
            for(User users:user){
                System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
            }
            List<User> user1=mapper.selectAll2();
            for(User users:user1){
                System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
            }                       
        } finally{
            // TODO Auto-generated catch block
            session.close();
        }
    }

声明了两个不同的 user 对象,但都是在同一个 Session 内执行查询的,代码虽然执行了两次数据库的查询,但是实际上只是在数据库查询了一次并将其缓存在同一 Session 中,再使用同一个 Session 查询同一字段时直接读取一级缓存中的数据内容。

一级缓存.png

总共打印了18条数据,从 log4j 的打印结果可以看出从数据库中查询出9条数据,并且只是发送了一次 SQL 语句。
注意:
1. 用同一 Session 但查询条件不同缓存失效
2. 用同一 Session 在第二次查询前执行了任何造成数据库改动的操作(CRDU)
再使用同一句查询语句缓存失效

二、Mybatis 二级缓存

如果要实现 mybatis 的二级缓存,二级缓存需要手动开启和配置,它是基于 namespace 级别的缓存,全局作用域缓存,一般来说有两种方式 :

  1. 采用 mybatis 内置的 cache 机制
  2. mybatis 定义了缓存接口 Cache,我们可以通过实现 Cache 接口来定义二级缓存,可采用第三方 Cache 框架。
  • 采用 mybatis 内置的 cache 机制

在表映射文件中加入 <cache /> 语句,并且相应的 model 要实现 java 的 Serializable 接口,因为二级缓存就是序列化和反序列化的过程,<cache /> 表示:

  1. 所有在映射文件里的 select 语句都将被缓存
  2. 所有在映射文件里的 insert,update 和 delete 语句会被清空缓存。
  3. 缓存不会被设定的时间所清空。
  4. 每个缓存可以存储 1024 个列表或对象的引用
  5. 缓存将作为 “读/写” 缓存,意味着获取对象不是共享的且对调用者是安全的,不会有其他的调用者或线程潜在修改。

使用步骤 :

  1. 全局配置文件中开启二级缓存,默认是打开的
    <setting name="cacheEnabled" value="ture" />
  2. 需要使用二级缓存的映射文件处理使用 cache 配置缓存
  3. POJO需要实现 Serializable 接口
  4. 如果会话关闭:一级缓存的数据会保存到二级缓存中,新的会话查询信息就可以参照二级缓存中的内容,二级缓存会在 SqlSession 关闭或提交后才会生效。

bean.java 实现序列化

public class User implements Serializable{
    private Integer id;
    private String username;
    private String password;
    private Integer sid;
    
    private School school;
    
    
    public User() {
                
    }
}

config.xml

<settings>
    
    <setting name="cacheEnabled" value="true"></setting>
    
</settings> 

Mapping.xml 配置 <cache /> 标签

<mapper namespace="cn.softjx.dao.inter.UserMapping">
    
<cache />                  
    <resultMap type="cn.softjx.modle.User" id="UserMap">
        <result column="t_id" property="id"/>
        <result column="t_username" property="username"/>
        <result column="t_password" property="password"/>
        <result column="t_sid" property="sid"/>
       ......

在 Test.java 中声明三个不同的 session 执行相同的查询

                User useBean=new User();
                useBean.setId(4);
                List<User> user=mapper.selectAll3(useBean);
                for(User users:user){
                    System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
                }
                                            
                
                session.close();
                
                UserMapping mapper1=session1.getMapper(UserMapping.class);
                
                List<User> user1=mapper1.selectAll3(useBean);
                for(User users:user1){
                    System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
                }
                                                
                session1.close();
            
                UserMapping mapper2=session2.getMapper(UserMapping.class);              
                List<User> user2=mapper2.selectAll3(useBean);
                for(User users:user2){
                    System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
                }                                                               
                session2.close();
结果.png image.png

虽然使用了不同的 Session 但只发送了一条 SQL。即不同的sqlSession可以共享一个 Mapping
日志中有一个 Hit Ratio 命中率,它是如何计算的呢。第一次查询由于缓存中是没有数据的所以是 0.0,第二次查询从缓存中取 1-(1/2)=0.5,第三次查询
1-(1/3)=0.666666

cache 标签中还有几个属性 eviction , flushInterval ,readOnly

  • eviction:
  1. LRU :最近不使用的缓存数据,移出最长时间不被使用的数据
  2. FIFO :先进先出
  3. SOFT : 软引用,移除基于垃圾回收器状态和软引用规则对象
  4. WEAK :软引用,更积极的垃圾回收器状态和软引用规则对象
    ,默认是 LRU
  • flushInterval :缓存刷新清空时间,默认不刷新

  • readOnly :是否进行只读操作,如果只进行只读操作当数据库内的值发送变化时,缓存值马上改变得到的数据还是原有的为进行修改的数据。

上篇:Mybatis (三)动态sql:http://www.jianshu.com/p/71c0cdd9c249

相关文章

网友评论

    本文标题:Mybatis (四) 缓存机制

    本文链接:https://www.haomeiwen.com/subject/omdabxtx.html