第五章
中分别有讲到select和insert的执行流程,并分别都会走到 SimpleExecutor 类的 doQuery 和 doUpdate 方法,先贴出这两个方法
**doQuery **
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// doQuery 和 doUpdate 都有这行代码,作用是创建语句处理器,看章节`6.1`
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 预编译语句,有过jdbc开发经验的就了解了,从这里开始,就是jdbc的操作封装了,看章节`6.2`
stmt = prepareStatement(handler, ms.getStatementLog());
// 查询就执行 StatementHandler 的 query 方法,看章节`6.3`
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
**doUpdate **
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// doQuery 和 doUpdate 都有这行代码,作用是创建语句处理器,看章节`6.1`
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 预编译语句,看章节`6.2`
stmt = prepareStatement(handler, ms.getStatementLog());
// 更新(insert|update|delete)就执行 StatementHandler 的 update 方法,看章节`6.4`
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
6.1 newStatementHandler创建语句处理器
configuration.newStatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 进一步创建RoutingStatementHandler,往下走
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 执行插件链
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
new RoutingStatementHandler
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、PreparedStatementHandler、CallableStatementHandler 三个类各自都继承 BaseStatementHandler 类,并且它们的构造函数中都没有做其他处理,都是直接super调用父类构造函数,那直接看父类 BaseStatementHandler 的构造函数实现。
BaseStatementHandler构造函数
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 下面4行,都是赋值
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
// 下面2行,分别拿到类型处理器和对象工厂
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
// 这一行是针对语句中,有对 selectKey设置,并且是执行前的操作时,才要处理
generateKeys(parameterObject);
// 获取boundSql,前面章节`5.1.1.1-1`有讲过,可以回头去看下
boundSql = mappedStatement.getBoundSql(parameterObject);
}
// 赋值
this.boundSql = boundSql;
// 创建参数处理器,比较简单,只提供了设置和获取参数两种操作,内部也有对插件链的执行
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 创建结果集处理器,细节待`第七章`中讲
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
6.2 prepareStatement预编译语句
SimpleExecutor.prepareStatement 方法
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 拿到链接,这里可能读者要问,connection 哪里来的,请回头看看章节`4.3`
Connection connection = getConnection(statementLog);
// 这一步会走到 BaseStatementHandler.prepare 方法,看章节`6.2.1`
stmt = handler.prepare(connection, transaction.getTimeout());
// 参数化,这一步调的是 RoutingStatementHandler.parameterize 方法,看章节`6.2.2`
handler.parameterize(stmt);
return stmt;
}
6.2.1 BaseStatementHandler.prepare
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// instantiateStatement 方法是一个 protected abstract 的抽象方法,由子类 SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler 各自实现,章节`6.2.1.1` 至 章节`6.2.1.3` 分别讲述三个子类的实现
statement = instantiateStatement(connection);
// 拿到 statement 后,给它设置超时时间
setStatementTimeout(statement, transactionTimeout);
// 设置获取结果的大小:fetchSize 这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)
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 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);
}
6.2.1.1 SimpleStatementHandler.instantiateStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
/* 这里涉及一个知识点:结果集类型(ResultSetType),官网描述:
FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)
FORWARD_ONLY:结果集只能单方向向前遍历
SCROLL_SENSITIVE:结果集可随意遍历并修改
SCROLL_INSENSITIVE:结果集可随意遍历,但不可修改
DEFAULT:未设置(依赖数据库驱动)
*/
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
// 这一行就是写jdbc时要用的,创建 Statement
return connection.createStatement();
} else {
// 根据结果集类型创建 Statement
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
6.2.1.2 PreparedStatementHandler.instantiateStatement
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() == ResultSetType.DEFAULT) {
// 直接看这里吧,熟悉的人都知道,这又是写jdbc时的代码
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
6.2.1.3 CallableStatementHandler.instantiateStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
// 又是写jdbc时的代码
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareCall(sql);
} else {
return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
6.2.2 RoutingStatementHandler.parameterize
public void parameterize(Statement statement) throws SQLException {
// 这里的 delegate 分别表示 SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler,所以又得分化成三种实现。SimpleStatementHandler 没有具体实现;CallableStatementHandler 关于存储过程的,由读者自行扩展;那么就剩下 PreparedStatementHandler 的实现了,其内部是调用的 DefaultParameterHandler.setParameters 方法,所以,直接讲这个方法
delegate.parameterize(statement);
}
DefaultParameterHandler.setParameters
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
// 从 boundSql 中取出参数映射列表 parameterMappings
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();
// 针对 DynamicSqlSource 的额外参数(其实这个,可以自定义,比如定义成一个Map传参,但是定义的时候,要注意key只能是“_parameter”)
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
// 获得对应额外参数值
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
// 没有参数值,设Null
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
// 类型处理器中,有对应的类型,直接赋值,关于类型处理器的描述,可以进入TypeHandlerRegistry类源码看一下就知道了
value = parameterObject;
} else {
// 如果是普通对象,那就解析对象属性
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// 接下来就是java数据类型跟jdbc中类型的转换了
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 给参数设置值,这一步就会将java类型的数据转换成jdbc类型的
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}