《深入理解mybatis原理》一级缓存
MyBatis
提供了一级缓存、二级缓存 这两个缓存机制,能够很好地处理和维护缓存,以提高系统的性能。这里主要介绍一级缓存,深入源码,解析其实现原理。
一级缓存介绍及用处
  每当我们使用MyBatis
开启一次和数据库的会话,MyBatis
会创建出一个SqlSession
对象表示一次数据库会话。
  在一次数据库会话中,可能会反复执行完全相同的sql
查询,在大数据量的情况下,这会造成极大的资源浪费。为了解决这一问题,减少资源的浪费,MyBatis
会在表示会话的SqlSession
对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来。当下次查询的时候,如果判断先前有个完全一样的查询,会直接从缓存中直接将结果取出,返回给用户,不需要再进行一次数据库查询了。
  如下图所示,mybatis
在一次会话(即一个SqlSession
对象)中,会创建一个本地存储。对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否存在,如果存在则直接返回返回;否则则去查询数据库并将结果存入。
Myabtis中的一级缓存结构
  之前看到Mybatis
利用动态代理使用MapperMethod.execute
来执行所有的数据库操作。实际上继续往下阅读可以发现最底层是调用了SqlSession
中Executor
对象的相关方法。
  当创建了一个SqlSession
对象时,会在内部创建一个Executor
执行器对象,缓存信息Cache
就存储在这个对象中。SqlSession、Executor、Cache之间的关系如下列类图所示:
  如上述的类图所示,Executor
接口的实现类BaseExecutor
中拥有一个Cache
接口的实现类PerpetualCache
,来实现对缓存的维护。
下面是PeroetualCache
的源码:
1 | public class PerpetualCache implements Cache { |
可以发现源码十分简单,就是用一个Map
来实现存储,key
值为一次查询的唯一标识,value
则为一次查询的结果。
一级缓存生命周期
MyBatis
在开启一个数据库会话时,会创建一个新的SqlSession
对象,SqlSession
对象中会有一个新的Executor
对象,Executor
对象中持有一个新的PerpetualCache
对象;当会话结束时,SqlSession
对象及其内部的Executor
对象还有PerpetualCache
对象也一并释放掉。- 如果
SqlSession
调用了close()
方法,会释放掉一级缓存PerpetualCache
对象,一级缓存将不可用; - 如果
SqlSession
调用了clearCache()
,会清空PerpetualCache
对象中的数据,但是该对象仍可使用; SqlSession
中执行了任何一个update
操作(update()、delete()、insert()
) ,都会清空PerpetualCache
对象的数据,但是该对象可以继续使用;
一级缓存唯一标识(CacheKey)
  Mybatis
会对同一次会话中的相同查询进行缓存,那么Mybatis
是根据什么条件判断两次查询相同呢。
  以下为判断部分源码:
1 |
|
可以看到createCacheKey
方法有四个参数,也就是对应的判断条件:
- 传入的
statementId
(即接口名+方法名) - 查询时要求的结果集中的结果范围
- 这次查询所产生的最终要传递给JDBC
java.sql.Preparedstatement
的Sql语句字符串(boundSql.getSql()) - 传递给
java.sql.Statement
要设置的参数值
MyBatis
认为的完全相同的查询,不是指使用sqlSession
查询时传递给SqlSession
的所有参数值完完全全相同,你只要保证statementId
,rowBounds
,最后生成的SQL
语句,以及这个SQL
语句所需要的参数完全一致就可以了。