BaseStatementHandler:一个抽象类,只是实现了一些不涉及具体操做的方法sql
RoutingStatementHandler:相似路由器,根据配置文件来路由选择具体实现类SimpleStatementHandler、CallableStatementHandler和PreparedStatementHandler数据库
SimpleStatementHandler:就是直接使用普通的Statement对象,这样每次执行SQL语句都须要数据库对SQL进行预编译app
PrepareStatementHandler:使用PrepareStatement执行,虽然初次建立PrepareStatement时开销比较大,但在屡次处理SQL时只须要初始化一次,能够有效提升性能ide
CallableStatementHandler:使用CallableStatement执行,CallableStatement是用来执行存储过程的。性能
在每一个mapper节点能够设置statementType决定是否使用谁 ,以下fetch
<!-- statementType (可选配置,默认配置为PREPARED) STATEMENT,PREPARED 或 CALLABLE 的一个。 这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement, 默认值:PREPARED。 --> <select id="findUserById" resultType="com.lpf.entity.User" statementType="PREPARED"> select * from m_user where id = #{id} </select>
public interface StatementHandler { // 从链接中获取一个Statement对象 Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException; // 绑定Statement执行是所须要的参数 void parameterize(Statement statement) throws SQLException; // 批量执行SQL void batch(Statement statement) throws SQLException; // 执行update,delete,insert语句 int update(Statement statement) throws SQLException; // 执行select语句 <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException; <E> Cursor<E> queryCursor(Statement statement) throws SQLException; BoundSql getBoundSql(); // 获取封装的ParameterterHandler对象 ParameterHandler getParameterHandler(); }
BaseStatementHandler是一个抽象类,和Executor同样使用了模板设计方法。代码以下:this
public abstract class BaseStatementHandler implements StatementHandler { protected final Configuration configuration; protected final ObjectFactory objectFactory; protected final TypeHandlerRegistry typeHandlerRegistry; //将结果映射成结果对象 protected final ResultSetHandler resultSetHandler; // 使用传入的实参替换SQL语句中的? protected final ParameterHandler parameterHandler; // 记录执行sql的executor 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) { // issue #435, get the key before calculating the statement // 获取主键 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由具体的子类对象实现 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) { //ignore } } protected void generateKeys(Object parameter) { KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); ErrorContext.instance().store(); keyGenerator.processBefore(executor, mappedStatement, null, parameter); ErrorContext.instance().recall(); } }
在BaseStatementHandler中有一个对象叫ParameterHandler是用来设置参数规则的,当StatementHandler调用prepare方法以后,接下来就是调用它来进行设置参数。spa
public interface ParameterHandler { Object getParameterObject(); void setParameters(PreparedStatement ps) throws SQLException; }
getParameterObject是用来获取参数的,setParameters(PreparedStatement ps)是用来设置参数的,至关于对sql中全部的参数都执行ps.setXXX(value);设计
ParameterHandler的默认实现类是DefaultParameterHandler,其实现了接口中定义的两个方法。对象
getParameterObject是获取参数,这个参数值就是你传递进来的值,多是个实体、map或单个基本类型数据。
@Override public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); // 去除SQL中的参数映射列表 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) {//过滤掉存储过程当中的输出参数 Object value;//记录绑定的实参值 // 获取参数名称 String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params //获取参数值 value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { //若是是单个值则直接赋值 value = parameterObject; } else { // 获取对象中相应的属性值或查找map对象中的值 MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } //获取参数值对应的jdbc类型 TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { //设置参数值和jdbc类型的对应关系 typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
/** * RoutingStatementHandler的主要功能就是根据mapper文件中的Statement的配置,生成一个对应的StatementHandler * 能够是 SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler * 此类中的全部方法都是经过调用delegate对象的对应方法实现的 */ 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()); } } }
SimpleStatementHandler就是使用基本的Statement来执行query、batch、update等操做,其实现仍是比较简单的,SQL语句中是没有占位符的,因此相应 的paramterize()方法是空实现。
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.<E>handleResultSets(statement); } @Override public <E> Cursor<E> queryCursor(Statement statement) throws SQLException { String sql = boundSql.getSql(); statement.execute(sql); return resultSetHandler.<E>handleCursorResultSets(statement); } @Override protected Statement instantiateStatement(Connection connection) throws SQLException { if (mappedStatement.getResultSetType() != null) { return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } else { return connection.createStatement(); } } @Override public void parameterize(Statement statement) throws SQLException { // N/A } }
PreparedStatementHandler底层依赖PreparedStatement对象来完成数据库的相关操做,在调用parameterize()方法完成SQL语句的参数绑定,代码也比较简单。
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.<E> handleResultSets(ps); } @Override public <E> Cursor<E> queryCursor(Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.<E> 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() != null) { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } else { return connection.prepareStatement(sql); } } @Override public void parameterize(Statement statement) throws SQLException { parameterHandler.setParameters((PreparedStatement) statement); } }
CallableStatementHandler实际就是使用CallableStatement来执行SQL语句,固然它执行的是存储过程。
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.<E>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.<E>handleCursorResultSets(cs); resultSetHandler.handleOutputParameters(cs); return resultList; } @Override protected Statement instantiateStatement(Connection connection) throws SQLException { String sql = boundSql.getSql(); if (mappedStatement.getResultSetType() != null) { return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } else { return connection.prepareCall(sql); } } @Override public void parameterize(Statement statement) throws SQLException { //注册out参数 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); //处理存储过程的INOUT和OUT 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()); } } } } } } }