根据前文的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下BaseExecutor如何解析执行sql语句
BaseExecutor-抽象类
其是Executor
接口的实现类但为抽象类,另外一个则为具体实现类为CachingExecutor
,主要是通过对象适配的设计模式在原来的executor上再附上缓存的属性,有兴趣的可自行查阅。先从构造函数看一发
protected BaseExecutor(Configuration configuration, Transaction transaction) { //事务对象 this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue(); this.localCache = new PerpetualCache("LocalCache"); this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); //表明exector的状态 this.closed = false; //主文件属性,主要获取MappedStatement对象 this.configuration = configuration; this.wrapper = this; }
BaseExecutor#update()-SqlSession之insert/update/delete入口
具体源码如下
@Override public int update(MappedStatement ms, Object parameter) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } clearLocalCache(); //供子类复写执行CUD操作 return doUpdate(ms, parameter); }
BaseExecutor#query()-SqlSession之select入口
具体源码如下
@Override publicList query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //获取绑定的sql,并将参数对象与sql语句的#{}一一对应 BoundSql boundSql = ms.getBoundSql(parameter); //获取cacheKey供缓存,包含完整的语句、参数等 CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); //比原先多传入CacheKey和BoundSql参数 return query(ms, parameter, rowBounds, resultHandler, key, boundSql); }
具体的查询处理逻辑如下
@Override publicList 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 list; try { queryStack++; //如果查询的语句已存在本地缓存中,则直接从本地获取,反之从数据库中读取内容 list = resultHandler == null ? (List ) localCache.getObject(key) : null; if (list != null) { //此处尝试对Callable类型的表达式进行处理,主要是针对mode=out类型的参数 //此参数主要是通过map来定义,直接从map中获取 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //从数据库中获取并进行缓存处理,其也会调用子类需复写的doQuery()方法 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对CRUD操作均转化为对子类的doUpdate()/doQuery()方法的调用,并一般都会相应的结果进行缓存以免频繁请求数据库导致性能下降。本文则从SimpleExecutor子类来进行分析
SimpleExecutor
分别看下SimpleExecutor复写的doUpdate()和doQuery()方法,具体源码如下
doUpdate()@Override public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Configuration configuration = ms.getConfiguration(); //创建StatementHandler来处理update() StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); //创建表达式对象Statement Statement stmt = prepareStatement(handler, ms.getStatementLog()); return handler.update(stmt); }
doQuery()
@Override publicList doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Configuration configuration = ms.getConfiguration(); //创建StatementHandler来处理query() StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); //创建表达式对象Statement Statement stmt = prepareStatement(handler, ms.getStatementLog()); return handler. query(stmt, resultHandler); }
doUpdate()/doQuery()代码的执行逻辑一致,均是先创建
StatementHandler
对象,然后通过prepareStatement()
方法创建表达式对象,供前者调用处理update/query方法
SimpleExecutor#prepareStatement()-创建预表达式对象
逻辑如下
//handler对象对应的为RoutingStatementHandler对象,其实也是个适配管理类 //可根据MappedStatement的statementType来确定表达式处理handler类,后续讲解 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; //获取连接对象,如果该日志等级为debug,则会打印相应的处理日志,采用代理实现 Connection connection = getConnection(statementLog); //创建真实的Statement对象,比如SimpleStatement/PreparedStatement/CallableStatement stmt = handler.prepare(connection, transaction.getTimeout()); //请求参数,常用在preparedStatement用来设置相应的请求参数 handler.parameterize(stmt); return stmt; }
小结
BaseExecutor抽象类提供了对CRUD操作的入口,并带有缓存效应,子类只需要复写doUpdate()和doQuery()抽象方法即可
SimpleExecutor-简单的处理实现类,即基本每次对相同的sql语句都会创建新的Statement对象;ReuseExecutor-复用处理实现类,即对相同的sql语句会缓存Statement对象;BatchExecutor-批处理实现类
最终获取Statement对象以及执行sql语句的解释权在于
StatementHandler
接口,详情看下节内容