Mybatis源码解析--StatementHandler
背景
概述
StatementHandler的分类
-
RoutingStatementHandler:更具不同的StatementType创建对应的StatementHandler(装饰者模式)
-
BaseStatementHandler:对公用逻辑的抽取
-
SimpleStatementHandler:用来处理
Statement
-
PreparedStatementHandler:用来处理
PreparedStatement
-
CallableStatementHandler:用来处理
CallableStatement
StatementHandler的创建
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); // 下面这行代码是根据插件对StatementHandler对象的增强,可以忽略掉 // statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }
直接创建了一个
RoutingStatementHandler
对象
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } }
在
RoutingStatementHandler
构造方法内根据不同的statementType创建对应的StatementHandler
,下面看一个各个StatementHandler
的创建过程
SimpleStatementHandler
public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); }
PreparedStatementHandler
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); }
CallableStatementHandler
public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); }
上面3个
StatementHandler
都调用父类的构造方法
BaseStatementHandler
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { this.configuration = mappedStatement.getConfiguration(); this.executor = executor; this.mappedStatement = mappedStatement; this.rowBounds = rowBounds; this.typeHandlerRegistry = configuration.getTypeHandlerRegistry(); this.objectFactory = configuration.getObjectFactory(); if (boundSql == null) { generateKeys(parameterObject); boundSql = mappedStatement.getBoundSql(parameterObject); } this.boundSql = boundSql; this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql); this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql); }
父类构造器中出现了几个重要的对象:
TypeHandlerRegistry:管理着Mybatis所有的类型处理器,类型处理器提供了jdbc类型与java类型的互转
ParameterHandler:用于给
PrepareStatement
对象设置参数ResultSetHandler:用于处理
ResultSet
,解析成java对象
StatementHandler与JDBC
StatementHandler
顾名思义就是对Statement
的处理,而JDBC规范中提供了3种Statement,他们之间的关系如下:
-
Statement:用于执行不带参数的简单SQL语句
-
PreparedStatement:
-
CallableStatement:
上面介绍了3种
Statement
对象,Mybatis针对这3种Statement
分别提供了3种对应的处理类对其处理,他们的处理关系如下:
在JDBC这篇文章中演示过一个demo,里面使用JDBC操作数据库,会发现每个Statement
对象的生命周期都要经过创建Statement
、设置参数、执行、解析结果集流程。而StatementHandler
是对Statement
处理的封装,说明它要提供相同的功能才能实现相同的效果,通过该接口提供的API也能印证这一点。
public interface StatementHandler { // 创建Statement Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException; // 设置参数 void parameterize(Statement statement) throws SQLException; // -----各种执行操作(开始)----- void batch(Statement statement) throws SQLException; int update(Statement statement) throws SQLException; <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException; <E> Cursor<E> queryCursor(Statement statement) throws SQLException; // -----各种执行操作(结束)----- BoundSql getBoundSql(); // 获取ParameterHandler,该对象主要是对Statement设置参数 ParameterHandler getParameterHandler(); }
除了接口中提供的这些功能,可以看出还少了一个对结果集的处理。其实在每个
StatementHandler
对象的执行操作方法中,可以看到它的身影。请参考SimpleStatementHandler
、PrepareStatementHandler
、CallableStatementHandler
的query
、queryCursor
等方法。
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { CallableStatement cs = (CallableStatement) statement; cs.execute(); List<E> resultList = resultSetHandler.handleResultSets(cs); resultSetHandler.handleOutputParameters(cs); return resultList; }
Mybatis组件关系图
通过上面的分析可以看出,Mybatis对
Statement
复杂的生命周期进行拆解,对生命周期中每个阶段的复杂逻辑使用分而治之的思想交给不同的类处理,使得每个类只关注自己分内的事。
小结
StatementHandler
是对JDBC中Statement
处理逻辑的封装,通过对Statement
不同阶段的拆解交给不同对象处理,从而达到解耦的目的
涉及到的编程思想:对复杂的处理逻辑分而治之