1.实现目的
这一节的目的主要是实现SqlSession级别的缓存,也就是一级缓存,首先看下图一,用户可以通过设置来进行是否开启一级缓存,不设置的化默认开启一级缓存,localCacheScope=SESSION为要设置一级缓存,localCacheScope=STATEMENT为不要设置一级缓存,(所以后面在清理缓存时会进行判断,如果是STATEMENT就删除缓存)。
2.简单说明
然后我们就需要解析下缓存设置,拿到缓存级别,执行Sql语句前,将按Mybatis的规定处理缓存key(id,参数,Sql语句,环境等等,生成对应hash值),然后判断缓存中是否有当前key的结果数据,有的化结果数据直接返回,没有的话就去执行数据库查询,然后将查询的结果存储到一级缓存Map中,然后判断缓存级别是否是STATEMENT,是的话代表不进行缓存操作,那此时删除,下次进来还是继续查询库,不是的话就不删除,留着继续执行同一SqlSession会话使用。
其实不算难,还是很简单,也很有调理,这就是设计的魅力,把每个类与属性现实化,那对应需要改动哪里,就都很清晰。
3.XML图
XML类图就是对应上面所说的逻辑的实现。
1.XMLConfigBuilder里专门解析设置操作,Configuration则是缓存级别的存储,此时需要用到LocalCacheScope枚举类,
2.Executor类里query方法添加一个参数缓存Key参数(CacheKey),然后在BaseExecutor里用没有缓存key参数的quey方法来获取缓存key的操作(这里获取就是生成,将对应需要的参数传到CacheKey类里处理Hash),得到后调用有缓存Key参数的query方法,这时此方法根据当前key去缓存查询是否有数据,有的话缓存拿出,没有执行queryFromDatabase方法,从数据库获取,获取完毕存储缓存里(存储Cache接口PerpetualCache类的map里)
4.代码实现
4.1 解析缓存设置
XMLConfigBuilder:解析配置XML构建器,这里需要添加私有方法settingsElement,主要解析缓存设置,解析完毕将缓存级别存储到configuration的LocalCacheScope枚举类下。
public class XMLConfigBuilder extends BaseBuilder {
// 省略其他方法
public Configuration parse() {
// STEP-17 添加设置
settingsElement(root.element("settings"));
}
/**
* 解析配置在 XML 文件中的缓存机制。并把解析出来的内容存放到 Configuration 配置项中。
* <settings>
* <!--缓存级别:SESSION/STATEMENT-->
* <setting name="localCacheScope" value="SESSION"/>
* </settings>
*/
private void settingsElement(Element context) {
if (context == null) return;
List<Element> elements = context.elements();
Properties props = new Properties();
for (Element element : elements) {
props.setProperty(element.attributeValue("name"), element.attributeValue("value"));
}
// 设置缓存级别
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope")));
}
}
Configuration:Configuration类里就针对缓存级别进行赋值操作。
public class Configuration {
// 缓存机制,默认不配置的情况是 SESSION
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
public LocalCacheScope getLocalCacheScope() {
return localCacheScope;
}
public void setLocalCacheScope(LocalCacheScope localCacheScope) {
this.localCacheScope = localCacheScope;
}
}
LocalCacheScope:缓存级别枚举,
/**
* @Author df
* @Description: 本地缓存机制;
* SESSION 默认值,缓存一个会话中执行的所有查询
* STATEMENT 不支持使用一级缓存,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不做数据共享
* @Date 2024/1/9 10:10
*/
// step 17添加
public enum LocalCacheScope {
SESSION,
STATEMENT
}
4.2 执行器缓存处理
Executor:
1.Executor类的修改是关于query方法时新添加缓存Key(CacheKey)操作,
2.添加了清除一级缓存方法定义以及创建缓存Key的方法定义
然后在BaseExecutor执行query时执行缓存存储,并根据参数生成缓存key,调用createCacheKey方法,增删改时删除缓存操作调用clearLocalCache方法。
public interface Executor {
// step-17 添加CacheKey参数
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql bo