StatementHandler解析
接口的作用是statement处理器,位于mybatis包的org.apache.ibatis.executor.statement目录下,源码如下:
1 package org.apache.ibatis.executor.statement; 2 3 import java.sql.Connection; 4 import java.sql.SQLException; 5 import java.sql.Statement; 6 import java.util.List; 7 8 import org.apache.ibatis.executor.parameter.ParameterHandler; 9 import org.apache.ibatis.mapping.BoundSql; 10 import org.apache.ibatis.session.ResultHandler; 11 12 public interface StatementHandler { 13 14 //sql预编译,构建Statement对象 15 Statement prepare(Connection connection) 16 throws SQLException; 17 18 //对prepare方法构建的预编译的SQL进行参数的设置 19 void parameterize(Statement statement) 20 throws SQLException; 21 22 //批量处理 23 void batch(Statement statement) 24 throws SQLException; 25 26 //执行预编译后的SQL--update语句 27 int update(Statement statement) 28 throws SQLException; 29 30 //执行预编译后的SQL--select语句 31List query(Statement statement, ResultHandler resultHandler) 32 throws SQLException; 33 34 //获取SQL封装类BoundSql对象 35 BoundSql getBoundSql(); 36 37 //获取参数处理器对象 38 ParameterHandler getParameterHandler(); 39 40 }
可见StatementHandler的作用就是先通过prepare方法构建一个Statement对象,然后再调用其他方法对Statement对象进行处理
StatementHandler和Executor类似,StatementHandler也有两个实现类,BaseStatementHandler和RoutingStatementHandler
而BaseStatement又有三个子类实现它的抽象方法,下面再挨个分析,先看最简单的BaseStatementHandler
BaseStatementHandler解析
BaseStatementHandler是一个抽象父类,有三个子类继承于它,源码如下:
1 package org.apache.ibatis.executor.statement; 2 3 import java.sql.Connection; 4 import java.sql.SQLException; 5 import java.sql.Statement; 6 7 import org.apache.ibatis.executor.ErrorContext; 8 import org.apache.ibatis.executor.Executor; 9 import org.apache.ibatis.executor.ExecutorException; 10 import org.apache.ibatis.executor.keygen.KeyGenerator; 11 import org.apache.ibatis.executor.parameter.ParameterHandler; 12 import org.apache.ibatis.executor.resultset.ResultSetHandler; 13 import org.apache.ibatis.mapping.BoundSql; 14 import org.apache.ibatis.mapping.MappedStatement; 15 import org.apache.ibatis.reflection.factory.ObjectFactory; 16 import org.apache.ibatis.session.Configuration; 17 import org.apache.ibatis.session.ResultHandler; 18 import org.apache.ibatis.session.RowBounds; 19 import org.apache.ibatis.type.TypeHandlerRegistry; 20 21 public abstract class BaseStatementHandler implements StatementHandler { 22 23 protected final Configuration configuration;//全局配置 24 protected final ObjectFactory objectFactory;//对象工厂 25 protected final TypeHandlerRegistry typeHandlerRegistry; 26 protected final ResultSetHandler resultSetHandler;//结果集处理器 27 protected final ParameterHandler parameterHandler;//参数处理器 28 29 protected final Executor executor;//执行器 30 protected final MappedStatement mappedStatement;//mapper的SQL对象 31 protected final RowBounds rowBounds;//分页参数 32 33 protected BoundSql boundSql;//sql封装对象 34 35 //构造方法 36 protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 37 this.configuration = mappedStatement.getConfiguration(); 38 this.executor = executor; 39 this.mappedStatement = mappedStatement; 40 this.rowBounds = rowBounds; 41 42 this.typeHandlerRegistry = configuration.getTypeHandlerRegistry(); 43 this.objectFactory = configuration.getObjectFactory(); 44 45 if (boundSql == null) { // issue #435, get the key before calculating the statement 46 generateKeys(parameterObject); 47 boundSql = mappedStatement.getBoundSql(parameterObject); 48 } 49 50 this.boundSql = boundSql; 51 52 this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql); 53 this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql); 54 } 55 56 //返回boundSql 57 public BoundSql getBoundSql() { 58 return boundSql; 59 } 60 61 //返回parameterHandler 62 public ParameterHandler getParameterHandler() { 63 return parameterHandler; 64 } 65 66 //预编译SQL语句 67 public Statement prepare(Connection connection) throws SQLException { 68 ErrorContext.instance().sql(boundSql.getSql()); 69 Statement statement = null; 70 try { 71 statement = instantiateStatement(connection);//调用抽象方法构建statement对象是,但是没有具体实现,而是交给其子类去实现 72 setStatementTimeout(statement);//设置statement超时时间 73 setFetchSize(statement);//设置statement的fetchSize 74 return statement; 75 } catch (SQLException e) { 76 closeStatement(statement); 77 throw e; 78 } catch (Exception e) { 79 closeStatement(statement); 80 throw new ExecutorException("Error preparing statement. Cause: " + e, e); 81 } 82 } 83 84 protected abstract Statement instantiateStatement(Connection connection) throws SQLException; 85 86 //给statement对象设置timeout 87 protected void setStatementTimeout(Statement stmt) throws SQLException { 88 Integer timeout = mappedStatement.getTimeout(); 89 Integer defaultTimeout = configuration.getDefaultStatementTimeout(); 90 if (timeout != null) { 91 stmt.setQueryTimeout(timeout); 92 } else if (defaultTimeout != null) { 93 stmt.setQueryTimeout(defaultTimeout); 94 } 95 } 96 97 //给statement对象设置fetchSize 98 protected void setFetchSize(Statement stmt) throws SQLException { 99 Integer fetchSize = mappedStatement.getFetchSize(); 100 if (fetchSize != null) { 101 stmt.setFetchSize(fetchSize); 102 } 103 } 104 105 //关闭statement 106 protected void closeStatement(Statement statement) { 107 try { 108 if (statement != null) { 109 statement.close(); 110 } 111 } catch (SQLException e) { 112 //ignore 113 } 114 } 115 116 //根据参数对象生成key 117 protected void generateKeys(Object parameter) { 118 KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); 119 ErrorContext.instance().store(); 120 keyGenerator.processBefore(executor, mappedStatement, null, parameter); 121 ErrorContext.instance().recall(); 122 } 123 124 }
可以看出BaseStatementHandler只是实现了StatementHandler的三个方法,其中getBoundSql和getParameterHandler方法只是返回了由构造方法初始化的boundSql和parameterHandler属性,
而prepare方法是用于构建Statement对象的,但是BaseStatementHandler只是调用了自身的抽象方法instantiateStatement来创建,然后对statement对象进行其他处理,但是创建的过程则没有实现,而是交给了其子类去实现。
BaseStatementHandler有三个子类,分别为:
SimpleStatememtHandler:最简单的StatementHandler,处理不带参数运行的SQL
PreparedStatementHandler:预处理Statement的handler,处理带参数允许的SQL
CallableStatementHandler:存储过程的Statement的handler,处理存储过程SQL
先来看最简单的SimpleStatementHandler,它继承于BaseStatementHandler,所以它需要实现StatementHandler的接口,还需要重写父类BaseStatementHandler的抽象方法,源码如下:
1 package org.apache.ibatis.executor.statement; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 import java.util.List; 8 9 import org.apache.ibatis.executor.Executor; 10 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; 11 import org.apache.ibatis.executor.keygen.KeyGenerator; 12 import org.apache.ibatis.executor.keygen.SelectKeyGenerator; 13 import org.apache.ibatis.mapping.BoundSql; 14 import org.apache.ibatis.mapping.MappedStatement; 15 import org.apache.ibatis.session.ResultHandler; 16 import org.apache.ibatis.session.RowBounds; 17 18 public class SimpleStatementHandler extends BaseStatementHandler { 19 20 //构造方法执行父类的构造方法 21 public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 22 super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); 23 } 24 25 //执行update操作 26 public int update(Statement statement) 27 throws SQLException { 28 String sql = boundSql.getSql(); 29 Object parameterObject = boundSql.getParameterObject(); 30 KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); 31 int rows; 32 //最终都是执行statement的getUpdateCount方法 33 if (keyGenerator instanceof Jdbc3KeyGenerator) { 34 statement.execute(sql, Statement.RETURN_GENERATED_KEYS); 35 rows = statement.getUpdateCount(); 36 keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject); 37 } else if (keyGenerator instanceof SelectKeyGenerator) { 38 statement.execute(sql); 39 rows = statement.getUpdateCount(); 40 keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject); 41 } else { 42 statement.execute(sql); 43 rows = statement.getUpdateCount(); 44 } 45 return rows; 46 } 47 48 //给statement添加批量处理sql语句 49 public void batch(Statement statement) 50 throws SQLException { 51 String sql = boundSql.getSql(); 52 statement.addBatch(sql); 53 } 54 55 //执行查询语句 56 publicList query(Statement statement, ResultHandler resultHandler) 57 throws SQLException { 58 String sql = boundSql.getSql(); 59 statement.execute(sql);//statement.execute方法执行sql语句 60 return resultSetHandler. handleResultSets(statement); 61 } 62 63 //构造Statement对象 64 protected Statement instantiateStatement(Connection connection) throws SQLException { 65 //通过Connection来create一个Statement对象 66 if (mappedStatement.getResultSetType() != null) { 67 return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); 68 } else { 69 return connection.createStatement(); 70 } 71 } 72 73 //由于SimpleStatementHandler是处理没有参数的SQL,所以参数设置的方法无需任何处理 74 public void parameterize(Statement statement) throws SQLException { 75 // N/A 76 } 77 78 }
可以看出主要是通过Connection创建一个Statement对象,然后通过调用Statement的execute方法执行sql语句
再看下PreparedStatementHandler,源码如下
1 package org.apache.ibatis.executor.statement; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.sql.Statement; 8 import java.util.List; 9 10 import org.apache.ibatis.executor.Executor; 11 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; 12 import org.apache.ibatis.executor.keygen.KeyGenerator; 13 import org.apache.ibatis.mapping.BoundSql; 14 import org.apache.ibatis.mapping.MappedStatement; 15 import org.apache.ibatis.session.ResultHandler; 16 import org.apache.ibatis.session.RowBounds; 17 18 public class PreparedStatementHandler extends BaseStatementHandler { 19 20 //执行父类构造方法 21 public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 22 super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); 23 } 24 25 //执行update操作 26 public int update(Statement statement) throws SQLException { 27 PreparedStatement ps = (PreparedStatement) statement; 28 ps.execute(); 29 int rows = ps.getUpdateCount(); 30 Object parameterObject = boundSql.getParameterObject(); 31 KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); 32 keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject); 33 return rows; 34 } 35 36 //给preparedStatement对象添加批量处理sql语句 37 public void batch(Statement statement) throws SQLException { 38 PreparedStatement ps = (PreparedStatement) statement; 39 ps.addBatch(); 40 } 41 42 //执行preparedStatement的查询语句 43 publicList query(Statement statement, ResultHandler resultHandler) throws SQLException { 44 PreparedStatement ps = (PreparedStatement) statement; 45 ps.execute(); 46 return resultSetHandler. handleResultSets(ps); 47 } 48 49 //构建Statement的子类PreparedStatement对象 50 protected Statement instantiateStatement(Connection connection) throws SQLException { 51 String sql = boundSql.getSql(); 52 if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { 53 String[] keyColumnNames = mappedStatement.getKeyColumns(); 54 if (keyColumnNames == null) { 55 return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); 56 } else { 57 return connection.prepareStatement(sql, keyColumnNames); 58 } 59 } else if (mappedStatement.getResultSetType() != null) { 60 return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); 61 } else { 62 return connection.prepareStatement(sql); 63 } 64 } 65 66 //给Statement对象设置参数 67 public void parameterize(Statement statement) throws SQLException { 68 parameterHandler.setParameters((PreparedStatement) statement); 69 } 70 71 }
再看下RoutingStatementHandler,这个相当于一个StatementHandler的路由器,本身不实现任何功能,只是根据传入的参数来选择调用哪个类型的StatementHandler来处理,代码如下:
1 public class RoutingStatementHandler implements StatementHandler { 2 3 private final StatementHandler delegate; 4 5 public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 6 7 switch (ms.getStatementType()) { 8 case STATEMENT: 9 delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 10 break; 11 case PREPARED: 12 delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 13 break; 14 case CALLABLE: 15 delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 16 break; 17 default: 18 throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); 19 } 20 21 } 22 23 @Override 24 public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { 25 return delegate.prepare(connection, transactionTimeout); 26 } 27 28 @Override 29 public void parameterize(Statement statement) throws SQLException { 30 delegate.parameterize(statement); 31 } 32 33 @Override 34 public void batch(Statement statement) throws SQLException { 35 delegate.batch(statement); 36 } 37 38 @Override 39 public int update(Statement statement) throws SQLException { 40 return delegate.update(statement); 41 } 42 43 @Override 44 publicList query(Statement statement, ResultHandler resultHandler) throws SQLException { 45 return delegate. query(statement, resultHandler); 46 } 47 48 @Override 49 public Cursor queryCursor(Statement statement) throws SQLException { 50 return delegate.queryCursor(statement); 51 } 52 53 @Override 54 public BoundSql getBoundSql() { 55 return delegate.getBoundSql(); 56 } 57 58 @Override 59 public ParameterHandler getParameterHandler() { 60 return delegate.getParameterHandler(); 61 } 62 }
可见RoutingStatementHandler的作用就是在构造的时候根据Statement类型来创建不同的处理器,然后调用对应的处理器来进行操作。而在StatementHandler在初始化的时候,都是通过RoutingStatementHandler来进行路由的,Configuration中的创建StatementHandler代码如下:
1 public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 2 StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); 3 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); 4 return statementHandler; 5 }
再看看SimpleStatementHandler是如何执行sql语句的:
1 @Override 2 protected Statement instantiateStatement(Connection connection) throws SQLException { 3 if (mappedStatement.getResultSetType() != null) { 4 return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); 5 } else { 6 return connection.createStatement(); 7 } 8 }
先通过Collection创建Statement对象
1 @Override 2 publicList query(Statement statement, ResultHandler resultHandler) throws SQLException { 3 String sql = boundSql.getSql(); 4 statement.execute(sql); 5 return resultSetHandler. handleResultSets(statement); 6 }
然后通过Statement对象执行sql语句,最后通过ResultSetHandler对象来处理执行后的结果。