源码分析-Mybatis源码阅读-Statement语句处理器 一 语句处理器说明 语句处理器的代码在org.apache.ibatis.executor.statement
包下,在03 源码分析-Mybatis源码阅读-执行器 文章中已经有介绍该包下所有类的相关说明。
二 语句处理器相关源码解读 首先,先看一下语句处理器的UML图,如下图:
和执行器类似,在语句处理器中BaseStatementHandler
使用了模板方法模式,RoutingStatementHandler
使用了装饰模式,了解这两个模式有助于我们更容易阅读源码。
先来看语句处理器接口StatementHandler
的关键源码,看看它给我们提供了哪些方法,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public interface StatementHandler { 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 getParameterHandler () ; }
BaseStatementHandler
主要定义了获取Statement的模板方法,关键源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 public abstract class BaseStatementHandler implements StatementHandler { protected final Configuration configuration; protected final ObjectFactory objectFactory; protected final TypeHandlerRegistry typeHandlerRegistry; protected final ResultSetHandler resultSetHandler; protected final ParameterHandler parameterHandler; protected final Executor executor; protected final MappedStatement mappedStatement; protected final RowBounds rowBounds; protected BoundSql boundSql; 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); } @Override public BoundSql getBoundSql () { return boundSql; } @Override public ParameterHandler getParameterHandler () { return parameterHandler; } @Override public Statement prepare (Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null ; try { statement = instantiateStatement(connection); setStatementTimeout(statement, transactionTimeout); setFetchSize(statement); return statement; } catch (SQLException e) { closeStatement(statement); throw e; } catch (Exception e) { closeStatement(statement); throw new ExecutorException("Error preparing statement. Cause: " + e, e); } } protected abstract Statement instantiateStatement (Connection connection) throws SQLException ; protected void setStatementTimeout (Statement stmt, Integer transactionTimeout) throws SQLException { Integer queryTimeout = null ; if (mappedStatement.getTimeout() != null ) { queryTimeout = mappedStatement.getTimeout(); } else if (configuration.getDefaultStatementTimeout() != null ) { queryTimeout = configuration.getDefaultStatementTimeout(); } if (queryTimeout != null ) { stmt.setQueryTimeout(queryTimeout); } StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout); } protected void setFetchSize (Statement stmt) throws SQLException { Integer fetchSize = mappedStatement.getFetchSize(); if (fetchSize != null ) { stmt.setFetchSize(fetchSize); return ; } Integer defaultFetchSize = configuration.getDefaultFetchSize(); if (defaultFetchSize != null ) { stmt.setFetchSize(defaultFetchSize); } } protected void closeStatement (Statement statement) { try { if (statement != null ) { statement.close(); } } catch (SQLException e) { } } protected void generateKeys (Object parameter) { KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); ErrorContext.instance().store(); keyGenerator.processBefore(executor, mappedStatement, null , parameter); ErrorContext.instance().recall(); } }
SimpleStatementHandler
简单语句处理器,主要是处理了update过程中,不同的主键生成策略时,创建Statement的一些差异,确保主键能正常设置到参数对象中。源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 public class SimpleStatementHandler extends BaseStatementHandler { public SimpleStatementHandler (Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { super (executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); } @Override public int update (Statement statement) throws SQLException { String sql = boundSql.getSql(); Object parameterObject = boundSql.getParameterObject(); KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); int rows; if (keyGenerator instanceof Jdbc3KeyGenerator) { statement.execute(sql, Statement.RETURN_GENERATED_KEYS); rows = statement.getUpdateCount(); keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject); } else if (keyGenerator instanceof SelectKeyGenerator) { statement.execute(sql); rows = statement.getUpdateCount(); keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject); } else { statement.execute(sql); rows = statement.getUpdateCount(); } return rows; } @Override public void batch (Statement statement) throws SQLException { String sql = boundSql.getSql(); statement.addBatch(sql); } @Override public <E> List<E> query (Statement statement, ResultHandler resultHandler) throws SQLException { String sql = boundSql.getSql(); statement.execute(sql); return resultSetHandler.handleResultSets(statement); } @Override public <E> Cursor<E> queryCursor (Statement statement) throws SQLException { String sql = boundSql.getSql(); statement.execute(sql); return resultSetHandler.handleCursorResultSets(statement); } @Override protected Statement instantiateStatement (Connection connection) throws SQLException { if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { return connection.createStatement(); } else { return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } @Override public void parameterize (Statement statement) { } }
PrepareStatementHandler
预处理语句处理器其实与SimpleStatementHandler
差不多,只不过过程中创建的是预处理的Statement这一点区别,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 public class PreparedStatementHandler extends BaseStatementHandler { public PreparedStatementHandler (Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { super (executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); } @Override public int update (Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); int rows = ps.getUpdateCount(); Object parameterObject = boundSql.getParameterObject(); KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject); return rows; } @Override public void batch (Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.addBatch(); } @Override public <E> List<E> query (Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.handleResultSets(ps); } @Override public <E> Cursor<E> queryCursor (Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.handleCursorResultSets(ps); } @Override protected Statement instantiateStatement (Connection connection) throws SQLException { String sql = boundSql.getSql(); if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { String[] keyColumnNames = mappedStatement.getKeyColumns(); if (keyColumnNames == null ) { return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); } else { return connection.prepareStatement(sql, keyColumnNames); } } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { return connection.prepareStatement(sql); } else { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } @Override public void parameterize (Statement statement) throws SQLException { parameterHandler.setParameters((PreparedStatement) statement); } }
CallableStatementHandler
其实与PrepareStatementHandler
差不多,只不过多了对输出结果的回调处理,具体源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 public class CallableStatementHandler extends BaseStatementHandler { public CallableStatementHandler (Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { super (executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); } @Override public int update (Statement statement) throws SQLException { CallableStatement cs = (CallableStatement) statement; cs.execute(); int rows = cs.getUpdateCount(); Object parameterObject = boundSql.getParameterObject(); KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject); resultSetHandler.handleOutputParameters(cs); return rows; } @Override public void batch (Statement statement) throws SQLException { CallableStatement cs = (CallableStatement) statement; cs.addBatch(); } @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; } @Override public <E> Cursor<E> queryCursor (Statement statement) throws SQLException { CallableStatement cs = (CallableStatement) statement; cs.execute(); Cursor<E> resultList = resultSetHandler.handleCursorResultSets(cs); resultSetHandler.handleOutputParameters(cs); return resultList; } @Override protected Statement instantiateStatement (Connection connection) throws SQLException { String sql = boundSql.getSql(); if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { return connection.prepareCall(sql); } else { return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } @Override public void parameterize (Statement statement) throws SQLException { registerOutputParameters((CallableStatement) statement); parameterHandler.setParameters((CallableStatement) statement); } private void registerOutputParameters (CallableStatement cs) throws SQLException { List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); for (int i = 0 , n = parameterMappings.size(); i < n; i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) { if (null == parameterMapping.getJdbcType()) { throw new ExecutorException("The JDBC Type must be specified for output parameter. Parameter: " + parameterMapping.getProperty()); } else { if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) { cs.registerOutParameter(i + 1 , parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale()); } else { if (parameterMapping.getJdbcTypeName() == null ) { cs.registerOutParameter(i + 1 , parameterMapping.getJdbcType().TYPE_CODE); } else { cs.registerOutParameter(i + 1 , parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName()); } } } } } } }
RoutingStatementHandler
路由语句处理器,会根据映射语句MappedStatement
中的StatementType的类型,来创建不同的语句处理器,然后并未对具体的执行器做进一步的包装,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public class RoutingStatementHandler implements StatementHandler { private final StatementHandler delegate; 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()); } } @Override public Statement prepare (Connection connection, Integer transactionTimeout) throws SQLException { return delegate.prepare(connection, transactionTimeout); } @Override public void parameterize (Statement statement) throws SQLException { delegate.parameterize(statement); } @Override public void batch (Statement statement) throws SQLException { delegate.batch(statement); } @Override public int update (Statement statement) throws SQLException { return delegate.update(statement); } @Override public <E> List<E> query (Statement statement, ResultHandler resultHandler) throws SQLException { return delegate.query(statement, resultHandler); } @Override public <E> Cursor<E> queryCursor (Statement statement) throws SQLException { return delegate.queryCursor(statement); } @Override public BoundSql getBoundSql () { return delegate.getBoundSql(); } @Override public ParameterHandler getParameterHandler () { return delegate.getParameterHandler(); } }