一、整体架构
SqlSession是接口,里面各种增删改查接口,Executor里面是具体的实现
SimpleExecutor
@Test
public void test1() throws SQLException {
SimpleExecutor executor = new SimpleExecutor(configuration, jdbcTransaction);
//mapper中对应的方法
MappedStatement ms = configuration.getMappedStatement("com.alipay.mybatis.persion.mapper.PersonMapper.findALl");
List<Person> es = executor.doQuery(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(2));
executor.doQuery(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(2));
System.out.println(es.get(1));
}
可见进行了两次预处理
ReuseExecutor
@Test
public void test2() throws SQLException {
ReuseExecutor executor = new ReuseExecutor(configuration, jdbcTransaction);
//mapper中对应的方法
MappedStatement ms = configuration.getMappedStatement("com.alipay.mybatis.persion.mapper.PersonMapper.findALl");
List<Person> es = executor.doQuery(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(2));
executor.doQuery(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(2));
System.out.println(es.get(1));
}
只进行了一次预处理
BatchExexutor
对于修改操作进行批处理,只编译一次
BaseExecutor中定义了下面三个执行器中的一些公共方法,如获取连接,缓存
@Test
public void test3() throws SQLException {
Executor executor = new SimpleExecutor(configuration, jdbcTransaction);
//mapper中对应的方法
MappedStatement ms = configuration.getMappedStatement("com.alipay.mybatis.persion.mapper.PersonMapper.findALl");
executor.query(ms, 2, RowBounds.DEFAULT,Executor.NO_RESULT_HANDLER);
executor.query(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER);
}
可见只进行了一次编译,是因为query中有缓存的操作
BaseExecutor的query方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);//获取动态sql
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);//获取缓存的key
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);//调用重载
}
//重载的query
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;//获取本地一级缓存
if (list != null) {
//如果有缓存
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//如果没有缓存
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
//BaseExecutor
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
//走到了doQuery方法
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
//SimpleExecutor
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
二级缓存
二级缓存的实现在CachingExecutor里面实现,采用装饰着模式
二级缓存需要自己来配,属于外部缓存
@Test
public void test4() throws SQLException {
Executor executor = new SimpleExecutor(configuration, jdbcTransaction);
//走二级缓存
CachingExecutor cachingExecutor = new CachingExecutor(executor);
//mapper中对应的方法
cachingExecutor.query(ms, 2, RowBounds.DEFAULT,Executor.NO_RESULT_HANDLER);
cachingExecutor.commit(true);//先走二级缓存再走一级缓存,由于我没有配二级缓存所以不会生效
cachingExecutor.query(ms, 2, RowBounds.DEFAULT,Executor.NO_RESULT_HANDLER);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {//判断你有没有配二级缓存,有就走下面逻辑
//清空二级缓存的操作
flushCacheIfRequired(ms);
//判断你的缓存是否是打开的
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
//获取缓存的内容
List<E> list = (List<E>) tcm.getObject(cache, key);
//如果缓存的内容为空
if (list == null) {
//交给下一个执行器,就是BaseExecutor
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//没有就走一级缓存,一级缓存定义在BaseExecutor 就是BaseExecutor
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
小总结
SqlSession中的方法会间接调用executor的query方法,在CachingExecutor中的query实现了该方法,里面有二级缓存的逻辑,然后里面的delegate指向下一个执行器BaseExecutor,里面有一级缓存和获取连接等操作,调用query方法,query方法里面又有doQuery方法,这个doQuery方法由下面三个类中的一个来实现
通过sqlsession来调用
清空缓存的操作
**
一级缓存失效的情况,是你用spring没有用到事务,只要把查询都写到一个事务里面,缓存就会生效,一个事务对应一个连接,一个连接就对应一次会话
spring是如何调用mybatis的工厂的
mybatis缓存体系
会话不是线程安全的,所以一级缓存也不是线程安全的,所以无法跨线程使用
commit应该加在后面
StatementHandler
一个SqlSession对应一个Executor对应多个个StatementHandler
StatementHandler的定义
结果集映射
ResultSetHandler->DefaultResultSetHandler
Mybatis映射体系
结果集和Java对象的一个互相的映射
MeataObject结果集映射工具类
我们可以采用工具类就可以直接把object转化为Blog类
Author是一个类,可以给里面的属性name赋值
MetaObject源码解析
结果集映射ResultMap
动态sql
SqlSource解析流程
SqlNode语法树结构
Configuration配置体系
Configuration核心功能
Configuration组件的构建过程
MappedStatement的解析
它是解析sql的所以比较核心
插件的四大组件
分页插件编码
就是在预处理的时候对它进行一个拦截