mybatis缓存

缓存是一般的 ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压 力,缓存的重要性是不言而喻的。 Mybatis 会将相同查询条件的 SQL 语句的查询结果存储在 内存或者某种缓存介质当中,当下次遇到相同的查询 SQL 时候不在执行该 SQL,而是直接从 缓存中获取结果,减少服务器的压力,尤其是在查询越多、缓存命中率越高的情况下,使用 缓存对性能的提高更明显。

MyBatis 缓存方式分为一级缓存和二级缓存,同时也可配置关于缓存设置。

一级缓存是将结果缓存在 SqlSession 对象中,二级缓存是存储在 SqlSessionFactory 对象 中。 默认情况下, MyBatis 开启一级缓存,没有开启二级缓存。

当数据量大的时候可以借助一些第三方缓存技术来协助保存 Mybatis 的二级缓存数据。

一、一级缓存的使用

1、一级缓存的生命周期

一级缓存也叫本地缓存,My Batis 的一级缓存是在会话(SqlSession)层面进行缓存的。 My Batis 的一级缓存是默认开启的,不需要任何的配置。

  • My Batis 在开启一个数据库会话时,会创建一个新的 SqlSession 对象,SqlSession 对象中会有一个新的 Executor 对象。 Executor 对象中持有一个新的 PerpetualCache 对象;当会 话结束时,SqlSession 对象及其内部的 Executor 对象还有 PerpetualCache 对象也一并释 放掉。

  • 如果 SqlSession 调用了 close()方法,会释放掉一级缓存 PerpetualCache 对象,一级缓存将不可用。

  • 如果 SqlSession 调用了 clearCache(),会清空 PerpetualCache 对象中的数据,但是该对象仍可使用。

  • SqlSession 中执行了任何一 个 update 操作(update() 、 delete() 、 insert()) , 都会清空PerpetualCache 对象的数据,但是该对象可以继续使用。

2、如何判断两次查询是完全相同的查询

Mybatis 认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同 的两次查询。

  • 传入的 statementId。

  • 查询时要求的结果集中的结果范围。

  • 这次查询所产生的最终要传递给 Preparedstatement 的 Sql 语句字符串。

  • 传递的参数值

3、测试一级缓存

public class DeptMapperTest {
    SqlSession session;
    DeptMapper mapper;

    @org.junit.Before
    public void setUp() throws Exception {
        session = MybatisUtil.getConnection();
        mapper = session.getMapper(DeptMapper.class);
    }

    @Test
    public void testFindById(){
        Dept dept = mapper.findById(1);
        System.out.println("dept1:" + dept);
        mapper.addDept(new Dept(null, "明教", "光明顶"));
        session.commit();
        // 第二次查询,默认使用一级缓存
        Dept dept2 = mapper.findById(1);
        System.out.println("dept2:" + dept2);
    }

    @org.junit.After
    public void tearDown() throws Exception {
        MybatisUtil.closeConnection();
    }
}

运行结果及解析如下:

一级缓存失效的情况。执行DML操作(update、delete、insert语句)。

4、不同的连接之间无法共享一级缓存

public class DeptMapperTest {
    SqlSession session;
    DeptMapper mapper;

    @org.junit.Before
    public void setUp() throws Exception {
        session = MybatisUtil.getConnection();
        mapper = session.getMapper(DeptMapper.class);
    }

    @Test
    public void testFindById(){
        Dept dept = mapper.findById(1);
        System.out.println("dept1:" + dept);
       /* mapper.addDept(new Dept(null, "明教", "光明顶"));
        session.commit();*/
        // 第二次查询,默认使用一级缓存
        Dept dept2 = mapper.findById(1);
        System.out.println("dept2:" + dept2);
    }

    // 不同的连接之间没法共享一级缓存
    @Test
    public void testFindById2(){
        Dept dept = mapper.findById(1);
        System.out.println("dept11:" + dept);
       /* mapper.addDept(new Dept(null, "明教", "光明顶"));
        session.commit();*/
        // 第二次查询,默认使用一级缓存
        Dept dept2 = mapper.findById(1);
        System.out.println("dept22:" + dept2);
    }

    @org.junit.After
    public void tearDown() throws Exception {
        MybatisUtil.closeConnection();
    }
}

运行结果截图:

二、二级缓存的使用

My Batis 的二级缓存是 Application 级别的缓存,它可以提高对数据库查询的效率,以提 高应用的性能。 二级缓存是 SqlSessionFactory 上的缓存,可以是由一个 SqlSessionFactory 创 建的不同的 SqlSession 之间共享缓存数据。 默认并不开启。

SqlSession 在执行 commit()或者 close()的时候将数据放入到二级缓存。

你使用的第三方缓存库有哪些?

MemCached、OSCache、EHCache。

1、二级缓存的配置方式

二级缓存的开启需要进行配置,实现二级缓存的时候, MyBatis 要求缓存的 POJO 必须 是可序列化的, 也就是要求实现 Serializable 接口。 在映射配置文件中配置<cache/>就可以 开启缓存了

2、二级缓存特点

映射语句文件中的所有 select 语句将会被缓存。

映射语句文件中的所有 insert、 update 和 delete 语句会刷新缓存。

二级缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响

如果在加入<cache/>标签的前提下让个别 select 元素不使用缓存,可以使用 useCache

属性,设置为 false。

缓存会使用默认的 Least Recently Used(LRU,最近最少使用的)算法来收回。

根据时间表,比如 No Flush Interval,(CNFI 没有刷新间隔) ,缓存不会以任何时间顺序来刷新。

缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用

缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以安全的被调用者修改,不干扰其他调用者或线程所做的潜在修改。

3、cache标签的可选属性

属性含义默认值
type自定义缓存类,要求实现 org.apache.ibatis.cache.Cache 接口null
readOnly是否只读true:给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。 这提供了很重要的性能优势。false:会返回缓存对象的拷贝(通过序列化) 。 这会慢一些,但是安全false
eviction缓存策略LRU(默认) – 最近最少使用:移除最长时间不被使用的对象。FIFO – 先进先出:按对象进入缓存的顺序来移除它们。SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。LRU
flushInterval刷新间隔,毫秒为单位。 默认为 null,也就是没有刷新间隔,只有执行 update、 insert、 delete 语句才会刷新null
size缓存对象个数1024
blocking是否使用阻塞性缓存 BlockingCachetrue:在查询缓存时锁住对应的 Key,如果缓存命中了则会释放对应的锁, 否则会在查询数据库以后再释放锁,保证只有一个线程到数据库中查找指 定 key 对应的数据false:不使用阻塞性缓存,性能更好false

4、测试二级缓存

4.1 开启全局配置

mybatis_config.xml文件中配置

  <settings>
        <setting name="useGeneratedKeys" value="true"/>
        <setting name="logImpl" value="SLF4J"/>
        <setting name="cacheEnabled" value="true" />
    </settings>

4.2 映射中使用二级缓存

DeptMapper.xml文件中配置

4.3 要使用二级缓存的POJO必须实现序列化接口

Dept.java文件中配置

public class Dept implements Serializable {

4.4 不同连接使用二级缓存测试

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值