StatementHandler是mybatis的核心接口,是Executor接口实现的基础。Executor接口在SqlSession的实现基础,在缓存那一节我们有介绍,所以不在介绍了。
//获取Statement Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException; //绑定参数 void parameterize(Statement statement) throws SQLException; //批量执行 void batch(Statement statement) throws SQLException; //执行update、insert、delete语句 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(); ParameterHandler getParameterHandler();
RoutingStatementHandler
主要类似分发器,会根据MappedStatement中指定的statementType字段,创建对应的StatementHandler。
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()); } }
PreparedStatementHandler
依赖PreparedStatement完成数据库的操作,主要看下如何生成statement对象
protected Statement instantiateStatement(Connection connection) throws SQLException { //待执行的sql语句 String sql = boundSql.getSql(); //获取preparedStatement 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); } }
ParameterHandler
StatementHandler的实现类BaseStatementHandler中,依赖ParameterHandler和esultSetHandler,前者处理的是参数,后者处理返回值。我们这次只看下ParameterHandler。主要适用于参数的绑定。在BoudSql中Sql语句可能包含占位符,ParameterHandler则负责为占位符绑定实参,
public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); //参数映射表 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)) { //参数实际值 value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } //设置typeHandler TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { //参数绑定 typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException | SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
绑定参数后,就可以交给数据库执行了