Mybatis学习笔记-一级缓存

时间:2021-01-16 05:36:57

参考:http://blog.csdn.net/luanlouis/article/details/41280959

Mybatis是一个小巧、强大的ORM框架,主要功能与Hibernate类似,但比Hibernate更加灵活,简单。

我们都知道,数据库操作是一个应用中比较耗费资源的一点,Mybatis作为最好用的orm框架,当然在这方面也做了优化,同样,与hibernate类似,mybatis也提供了一级缓存和二级缓存来提高数据访问层(Dao)的性能。

下面详细介绍一个mybatis的一级缓存。

  • 一级缓存简述及引入一级缓存的原因。
    在某些情况下,我们需要在一次连接上进行多次相同的查询(虽然现在没想起来这样的场景,但它确实存在),这就意味着需要进行多次数据库操作,但是,重点在于多次查询的结果是相同的,这样的多次查询既没有意义有占用资源(数据库查询是非常耗费系统资源的),mybatis为了解决这个问题,就引入了以及缓存。

    每次查询时,mybatis会在SqlSession中创建一块缓存区,将查询接环缓存到这里,若在此次连接中有相同的查询,则直接从一级缓存总获取查询结果,不需要查询数据库,从而提高了系统性能和响应速度。

  • mybatis中一级缓存的组织形式

    mybatis的一级缓存是SqlSession对象内的一块内存区域,由于SqlSession代表了一次数据库连接,下面来看一下一级缓存与SqlSession的关系
    Mybatis学习笔记-一级缓存

    实际上,SqlSession只是mybatis对外提供的一个统一接口,对应执行sql语句的活儿都是交给Executor来处理的,这样一来,Executor顺理成章的维护一级Cache,图中的BaseExecutor是Executor的实现类,PerpetualCache是Cache接口的一个实现类。下面来看一下源代码就一目了然了。

public class DefaultSqlSession implements SqlSession {

private Configuration configuration;
//引入Executor
private Executor executor;
......
}
public abstract class BaseExecutor implements Executor {

private static final Log log = LogFactory.getLog(BaseExecutor.class);

// for backward compatibility with 3.0 style logging
private static final Log connectionLog = LogFactory.getLog(Connection.class);

protected Transaction transaction;

protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
//引入一级缓存
protected PerpetualCache localCache;
protected PerpetualCache localOutputParameterCache;
protected Configuration configuration;

protected int queryStack = 0;

protected List<BatchResult> batchResults = new ArrayList<BatchResult>();
private boolean closed;
}

小结,SqlSession包含Executor,Executor包含Cache。

  • 一级缓存的生命周期
    当SqlSession被创建时,一级缓存生命周期开始,当SqlSession被释放时,一级缓存生命周期结束。

    具体规则如下:
    a)调用SqlSession的close()方法,一级缓存被释放掉,一级缓存不可用。
    b)调用SqlSession的clearCache()方法,清空一级缓存,但一级缓存仍可用。
    c)执行DML的sql语句,会 清空缓存,但一级缓存可用。

  • 一级缓存的工作流程
    1)对于一个查询,根据statementId,params和rowBounds构建一个key
    2)根据这个key从cache(map)中获取数据。
    3)若结果不为空,则命中缓存,不再需要查询数据库。
    4)没有命中
    4.1)查询数据库,得到查询结果。
    4.2)将key和得到的查询结果(value)放入缓存中。
    4.3)返回结果。

  • 一级缓存的性能分析。
    a)mybatis的一级缓存是由map实现,相对简单,并且没有对容量的限制,那么这样会不会有由于map过大导致jvm内存溢出呢?mybatis这样设计当然有他的道理。
    a.1)一般来说,SqlSession对象不会存在太久,当执行完sql操作后就被释放掉了。
    a.2)只要执行DML操作,都会情况缓存。
    a.3)还可以手动清楚缓存中的内存(SqlSession的clearCache()方法)

b)mybatis的一级缓存是一个粗粒度的缓存,没有更新缓存和缓存过期等概念,所以在使用是,应该注意一下几点:
b.1)对于更新频率较大、且对数据准确性要求较高的,应尽量控制好SqlSession中一级缓存数据的存放时间,以免造成数据的误差。
b.2)对于频繁执行的大范围的select,尽量控制其结果在一级缓存中的存放时间,避免占用太多内存资源。