版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ashan_li/article/details/50379260
在SimpleExecutor中,执行SQL时调用preareStatement()方法来对statement进行初始化及参数设置。
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
//初始化
stmt = handler.prepare(connection);
//参数设置`
handler.parameterize(stmt);
return stmt;
}
这里PreparedStatementHandler为例。详细分析这两个过程。
Statement初始化
这是BaseStatementHandler.prepare()方法
public Statement prepare(Connection connection) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//通过connection得到一个statement
statement = instantiateStatement(connection);
//设置执行超时时间
setStatementTimeout(statement);
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);
}
}
再看PreparedStatementHandler.instantiateStatement()方法
protected Statement instantiateStatement(Connection connection) throws SQLException {
//被执行的SQL
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 {
//直接使用jdbc的方式获取了一个PreparedStatement对象
return connection.prepareStatement(sql);
}
}
Statement参数设置
如下是PreparedStatementHandler.parameterize()方法
public void parameterize(Statement statement) throws SQLException {
//直接调用了ParameterHandler的方法设置
parameterHandler.setParameters((PreparedStatement) statement);
}
DefaultParamterHandler.parameterize()方法
public void setParameters(PreparedStatement ps) throws SQLException {
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 {
//主要通过MetaObject对象从参数出取数据,MetaObject前面已经详细分析过!
MetaObject metaObject = configuration.newMetaObject(parameterObject);
//根据参数名称获取值
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
//调用对应的typeHandler设置参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
}
}
}
}
TypeHandler主要有两个功能:
- 设置sql执行时的参数
- 从结果集中取数据
public interface TypeHandler<T> {
//设置参数
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
//取数据
T getResult(ResultSet rs, String columnName) throws SQLException;
//取数据
T getResult(ResultSet rs, int columnIndex) throws SQLException;
//取数据
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
来看看类关系图就更清楚啦
这些都Mybatis内置的TypeHandler,我们也可以自定义一个!处置枚举类型可能很有用。具体的TypeHandler不做讨论。
小结
分析到这里,如果是执行update/insert/delete语句,那么整个过程基本上已经完成。如果是执行select语句,还有重要的两步:结果集映射及缓存!