Mybatis源码分析-BaseExecutor

根据前文Mybatis源码分析-SqlSessionTemplate的简单分析,对于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 public List 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 public List 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 public List 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/PrepareStatement/CallableStatement stmt = handler.prepare(connection, transaction.getTimeout()); //设置参数集合比如paramterMap标签 handler.parameterize(stmt); return stmt; } 小结 BaseExecutor抽象类提供了对CRUD操作的入口,并带有缓存效应,子类只需要复写doUpdate()和doQuery()抽象方法即可 SimpleExecutor-简单的处理实现类,即基本每次对相同的sql语句都会创建新的Statement对象;ReuseExecutor-复用处理实现类,即对相同的sql语句会缓存Statement对象;BatchExecutor-批处理实现类 最终获取Statement对象以及执行sql语句的解释权在于StatementHandler接口,详情看下节内容 作者:南柯问天 出处:http://www.cnblogs.com/question-sky/ 本文版权归本人和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 http://www.cnblogs.com/question-sky/p/7353418.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信