建议结合我的Mybaits__Executor源码跟踪解析一起看
Mybatis对数据库的操作,都将委托给执行器Executor来完成,所以执行器Executor是相当重要的,在Mybatis中,SqlSession对数据库的操作,将委托给执行器Executor来完成,Executor由五个不同功能的Executor完成,分别为:
1.基类执行器BaseExecutor
2.简单执行器SimpleExecutor
3. 重用执行器ReuseExecutor
4.批量执行器BatchExecutor
5. 缓存执行器CachingExecutor
6.无用执行器ClosedExecutor
概述
基类执行器BaseExecutor
采用模板方法的设计模式,抽象类,实现了Executor接口,实现了执行器的基本功能,
简单执行器SimpleExecutor
默认的执行器,最简单的执行器,每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。根据对应的sql直接执行即可,不会做一些额外的操作;拼接完SQL之后,直接交给 StatementHandler去执行。(可以是Statement或PrepareStatement对象)。
重用执行器ReuseExecutor
执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用。可重用的执行器,重用的对象是Statement,也就是说该执行器会缓存同一个sql的Statement,省去Statement的重新创建,优化性能。内部的实现是通过一个HashMap来维护Statement对象的。由于当前Map只在该session中有效,所以使用完成后记得调用flushStatements来清除Map。(可以是Statement或PrepareStatement对象)。
批量执行器BatchExecutor
执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),statementList它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理的;BatchExecutor相当于维护了多个包装箱,每个包装箱里都装了很多属于自己的SQL,就像篮球箱里装了很多篮球,足球箱里装了很多足球,最后统一放入仓库。(可以是Statement或PrepareStatement对象)
缓存执行器CachingExecutor
装饰设计模式典范,先从缓存中获取查询结果,存在就返回,不存在,再委托给Executor delegate去数据库取,delegate可以是上面任一的SimpleExecutor、ReuseExecutor、BatchExecutor。启用于二级缓存时的执行器;采用静态代理;代理一个 Executor 对象。执行 update 方法前判断是否清空二级缓存;执行 query 方法前先在二级缓存中查询,命中失败再通过被代理类查询。
无用执行器ClosedExecutor
毫无用处,仅作为一种标识,和Serializable标记接口作用相当。
作用范围
以上这执行器的作用范围,都严格限制在SqlSession生命周期范围内。
基类BaseExecutor源码解析
经典的模板设计模式,不同的实现类,分别实现自己的三个抽象方法即可:doUpdate()、doQuery()、doFlushStatement()。
// 定义的四个抽象方法,在相应方法中被调用,Update,FlushStatements,Query,QueryCursor
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException;
protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
throws SQLException;
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
BoundSql boundSql)
throws SQLException;