StatementHandler数据库交互
StatementHandler接口是mybatis的核心接口之一,StatementHandler接口中功能很多,进行预编译并且调用ParameterHandler的setParameters()方法设置参数,创建Statement对象,通过ParameterHandler为SQL语句绑定实参,执行select、insert、update、delete等多种类型的SQL语句,批量执行SQL语句,通过ResultSetHandler将结果集映射成结果对象。
StatementHandler流程
- 创建: 由Configuration方法中newStatementHandler()方法生成的,生成的是RoutingStatementHandler
- 选择: RoutingStatementHandler的通过适配器模式找到对应(根据上下文)的StatementHandler执行的,并且有SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler
- Executor会调用StatementHandler的prepare方法创建Statement,调用parameterize方法通过ParameterHandler设置参数,完成预编译(只有Statement为PreparedStatement时才会进行预编译)
- 最后调用ResultSetHandler封装结果集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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(); }
|
StatementHandler有两个实现类RoutingStatementHandler和BaseStatementHandler
BaseStatementHandler
BaseStatementHandler是实现了一个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 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 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 = this.configuration.getTypeHandlerRegistry(); this.objectFactory = this.configuration.getObjectFactory(); if (boundSql == null) { this.generateKeys(parameterObject); boundSql = mappedStatement.getBoundSql(parameterObject); }
this.boundSql = boundSql; this.parameterHandler = this.configuration.newParameterHandler(mappedStatement, parameterObject, boundSql); this.resultSetHandler = this.configuration.newResultSetHandler(executor, mappedStatement, rowBounds, this.parameterHandler, resultHandler, boundSql); }
public BoundSql getBoundSql() { return this.boundSql; }
public ParameterHandler getParameterHandler() { return this.parameterHandler; } public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(this.boundSql.getSql()); Statement statement = null;
try { statement = this.instantiateStatement(connection); this.setStatementTimeout(statement, transactionTimeout); this.setFetchSize(statement); return statement; } catch (SQLException var5) { this.closeStatement(statement); throw var5; } catch (Exception var6) { this.closeStatement(statement); throw new ExecutorException("Error preparing statement. Cause: " + var6, var6); } }
protected abstract Statement instantiateStatement(Connection var1) throws SQLException;
protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException { Integer queryTimeout = null; if (this.mappedStatement.getTimeout() != null) { queryTimeout = this.mappedStatement.getTimeout(); } else if (this.configuration.getDefaultStatementTimeout() != null) { queryTimeout = this.configuration.getDefaultStatementTimeout(); }
if (queryTimeout != null) { stmt.setQueryTimeout(queryTimeout); }
StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout); }
protected void setFetchSize(Statement stmt) throws SQLException { Integer fetchSize = this.mappedStatement.getFetchSize(); if (fetchSize != null) { stmt.setFetchSize(fetchSize); } else { Integer defaultFetchSize = this.configuration.getDefaultFetchSize(); if (defaultFetchSize != null) { stmt.setFetchSize(defaultFetchSize); }
} }
protected void closeStatement(Statement statement) { try { if (statement != null) { statement.close(); } } catch (SQLException var3) { }
}
protected void generateKeys(Object parameter) { KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator(); ErrorContext.instance().store(); keyGenerator.processBefore(this.executor, this.mappedStatement, (Statement)null, parameter); ErrorContext.instance().recall(); } }
|
在BoundSql中记录的SQL语句中可能包含”?”占位符,而每个”?”占位符都对应了BoundSql.parameterMappings集合中的一个元素,ParameterMapping对象中记录了对应参数的名称以及相关属性
在ParameterHandler中的setParameters方法负责为SQL语句绑定实参,该接口只有一个实现类DefaultParameterHandler,遍历BoundSql.parameterMappings集合,根据ParameterMapping对象中记录的参数名称查找相应的实参,通过TypeHandler转换为JdbcType
SimpleStatementHandler
SimpleStatementHandler继承了BaseStatementHandler抽象类,底层直接使用java.sql.Statement对象来操作数据库,SQL中不能存在占位符,parameterize方法为空实现
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
| 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); } public int update(Statement statement) throws SQLException { String sql = this.boundSql.getSql(); Object parameterObject = this.boundSql.getParameterObject(); KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator(); int rows; if (keyGenerator instanceof Jdbc3KeyGenerator) { statement.execute(sql, 1); rows = statement.getUpdateCount(); keyGenerator.processAfter(this.executor, this.mappedStatement, statement, parameterObject); } else if (keyGenerator instanceof SelectKeyGenerator) { statement.execute(sql); rows = statement.getUpdateCount(); keyGenerator.processAfter(this.executor, this.mappedStatement, statement, parameterObject); } else { statement.execute(sql); rows = statement.getUpdateCount(); }
return rows; }
public void batch(Statement statement) throws SQLException { String sql = this.boundSql.getSql(); statement.addBatch(sql); }
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { String sql = this.boundSql.getSql(); statement.execute(sql); return this.resultSetHandler.handleResultSets(statement); }
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException { String sql = this.boundSql.getSql(); statement.execute(sql); return this.resultSetHandler.handleCursorResultSets(statement); } protected Statement instantiateStatement(Connection connection) throws SQLException { return this.mappedStatement.getResultSetType() == ResultSetType.DEFAULT ? connection.createStatement() : connection.createStatement(this.mappedStatement.getResultSetType().getValue(), 1007); }
public void parameterize(Statement statement) { } }
|
PreparedStatementHandler
PreparedStatementHandler继承了BaseStatementHandler抽象类,底层使用java.sql.PreparedStatement对象来操作数据库,PreparedStatement是预编译的,可以在sql语句中存在”?”占位符,parameterize方法通过调用ParameterHandler.setParameters()方法完成SQL语句的参数绑定
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
| 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); }
public int update(Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement)statement; ps.execute(); int rows = ps.getUpdateCount(); Object parameterObject = this.boundSql.getParameterObject(); KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator(); keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject); return rows; }
public void batch(Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement)statement; ps.addBatch(); }
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement)statement; ps.execute(); return this.resultSetHandler.handleResultSets(ps); }
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement)statement; ps.execute(); return this.resultSetHandler.handleCursorResultSets(ps); } protected Statement instantiateStatement(Connection connection) throws SQLException { String sql = this.boundSql.getSql(); if (this.mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { String[] keyColumnNames = this.mappedStatement.getKeyColumns(); return keyColumnNames == null ? connection.prepareStatement(sql, 1) : connection.prepareStatement(sql, keyColumnNames); } else { return this.mappedStatement.getResultSetType() == ResultSetType.DEFAULT ? connection.prepareStatement(sql) : connection.prepareStatement(sql, this.mappedStatement.getResultSetType().getValue(), 1007); } }
public void parameterize(Statement statement) throws SQLException { this.parameterHandler.setParameters((PreparedStatement)statement); } }
|
CallableStatementHandler
CallableStatementHandler继承了BaseStatementHandler抽象类,底层使用java.sql.CallableStatement调用指定的存储过程,其parameterize方法通过调用ParameterHandler.setParameters()方法完成SQL语句的参数绑定,并指定输出参数的索引位置和JDBC类型。
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
| 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); }
public int update(Statement statement) throws SQLException { CallableStatement cs = (CallableStatement)statement; cs.execute(); int rows = cs.getUpdateCount(); Object parameterObject = this.boundSql.getParameterObject(); KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator(); keyGenerator.processAfter(this.executor, this.mappedStatement, cs, parameterObject); this.resultSetHandler.handleOutputParameters(cs); return rows; }
public void batch(Statement statement) throws SQLException { CallableStatement cs = (CallableStatement)statement; cs.addBatch(); }
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { CallableStatement cs = (CallableStatement)statement; cs.execute(); List<E> resultList = this.resultSetHandler.handleResultSets(cs); this.resultSetHandler.handleOutputParameters(cs); return resultList; }
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException { CallableStatement cs = (CallableStatement)statement; cs.execute(); Cursor<E> resultList = this.resultSetHandler.handleCursorResultSets(cs); this.resultSetHandler.handleOutputParameters(cs); return resultList; }
protected Statement instantiateStatement(Connection connection) throws SQLException { String sql = this.boundSql.getSql(); return this.mappedStatement.getResultSetType() == ResultSetType.DEFAULT ? connection.prepareCall(sql) : connection.prepareCall(sql, this.mappedStatement.getResultSetType().getValue(), 1007); }
public void parameterize(Statement statement) throws SQLException { this.registerOutputParameters((CallableStatement)statement); this.parameterHandler.setParameters((CallableStatement)statement); }
private void registerOutputParameters(CallableStatement cs) throws SQLException { List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings(); int i = 0;
for(int n = parameterMappings.size(); i < n; ++i) { ParameterMapping 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()); }
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
RoutingStatementHandler是StatementHandler接口的另一个实现类,会根据MappedStatement中指定的statementType来创建对应的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
| 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: this.delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: this.delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: this.delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); }
}
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { return this.delegate.prepare(connection, transactionTimeout); }
public void parameterize(Statement statement) throws SQLException { this.delegate.parameterize(statement); }
public void batch(Statement statement) throws SQLException { this.delegate.batch(statement); }
public int update(Statement statement) throws SQLException { return this.delegate.update(statement); }
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { return this.delegate.query(statement, resultHandler); }
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException { return this.delegate.queryCursor(statement); }
public BoundSql getBoundSql() { return this.delegate.getBoundSql(); }
public ParameterHandler getParameterHandler() { return this.delegate.getParameterHandler(); } }
|