您的位置:首页 > 数据库

Mybatis3源码分析(15)-Sql解析执行-Statement初始化和参数设置

2015-12-22 13:11 1031 查看
在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语句,还有重要的两步:结果集映射及缓存!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java jdbc mybatis sql 源码