Mybatis3.5.1源码分析
- Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
- Mybatis-Configuration源码解析
- Mybatis-事务对象源码解析
- Mybatis-数据源源码解析
- Mybatis缓存策略源码解析
- Mybatis-DatabaseIdProvider源码解析
- Mybatis-TypeHandler源码解析
- Mybatis-Reflector源码解析
- Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
- Mybatis-Mapper各类标签封装类源码解析
- Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
- Mybatis-MapperAnnotationBuilder源码分析
- [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
- Mybatis-LanguageDriver源码解析
- Mybatis-SqlSource源码解析
- Mybatis-SqlNode源码解析
- Mybatis-KeyGenerator源码解析
- Mybatis-Executor源码解析
- Mybatis-ParameterHandler源码解析
- Mybatis-StatementHandler源码解析
- Mybatis-DefaultResultSetHandler(一)源码解析
- Mybatis-DefaultResultSetHandler(二)源码解析
- Mybatis-ResultHandler,Cursor,RowBounds 源码分析
- Mybatis-MapperProxy源码解析
- Mybatis-SqlSession源码解析
- Mybatis-Interceptor源码解析
StatementHandler
/**
* Copyright 2009-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.statement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.session.ResultHandler;
/**
* StatementHandler负责处理Mybatis与JDBC之间Statement的交互,而JDBC中的Statement,就是负责与数据库进行交互的对象。
*
* 参考博客:
*
https://www.jianshu.com/p/19686af69b0d
*
*
* @author Clinton Begin
*/
public interface StatementHandler {
/**
* 根据MappedStatement对象配置的StatementType,去创建Statement对象或则PreparedStatment或则CallableStatment
* @param connection 数据库连接对象
* @param transactionTimeout 事务超时时间
*/
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
/**
* 主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改
* @param statement 执行SQL 语句并返回它所生成结果的对象
*/
void parameterize(Statement statement)
throws SQLException;
/**
* 将 {@code statement} 添加到批处理队列
* @param statement 执行SQL 语句并返回它所生成结果的对象
*/
void batch(Statement statement)
throws SQLException;
/**
* 用于通知Statement将[insert,update,delete]推送到数据库
* @param statement 执行SQL 语句并返回它所生成结果的对象
* @return 更新记录数
*/
int update(Statement statement)
throws SQLException;
/**
* 用于通知Statement将[select]推送到数据库并返回对应查询结果
* @param statement 执行 SQL 语句并返回它所生成结果的对象
* @param resultHandler 结果处理器
* @param 结果对象类型
* @return 结果对象集合
*/
List query(Statement statement, ResultHandler resultHandler)
throws SQLException;
/**
* 用于通知Statement将[select]推送到数据库并返回对应游标结果
* @param statement 执行 SQL 语句并返回它所生成结果的对象
* @param 结果对象类型
* @return 结果对象游标对象
* @throws SQLException
*/
Cursor queryCursor(Statement statement)
throws SQLException;
/**
* 获取参数映射与可执行SQL封装类对象
*/
BoundSql getBoundSql();
/**
* 获取参数处理器
*/
ParameterHandler getParameterHandler();
}
RoutingStatementHandler
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.statement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
/**
* 一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
* @author Clinton Begin
*/
public class RoutingStatementHandler implements StatementHandler {
/**
* 真正操作的StatementHandler
*/
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据StatementType去新建对应的StatmentHandler对象,
//ms.getStatementType默认是PREPARED
switch (ms.getStatementType()) {
case STATEMENT:
//简单的Statement处理器,Statement:用于执行静态 SQL 语句并返回它所生成结果的对象
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
//PreparedStatement对象处理器,PreparedStatement: 预编译的 SQL 语句的对象
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
//CallableStatement对象处理器,CallableStatmement:用于执行 SQL 存储过程的接口实例
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
//没有配置StatementType的ms还怎么执行,肯定要抛出异常啦
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
/**
* 创建Statement对象或则PreparedStatment或则CallableStatment
* @param connection 数据库连接对象
* @param transactionTimeout 事务超时时间
*/
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
//交由delegate处理
return delegate.prepare(connection, transactionTimeout);
}
/**
* 主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改
* @param statement 执行SQL 语句并返回它所生成结果的对象
*/
@Override
public void parameterize(Statement statement) throws SQLException {
//交由delegate处理
delegate.parameterize(statement);
}
/**
* 将 {@code statement} 添加到批处理队列
* @param statement 执行SQL 语句并返回它所生成结果的对象
*/
@Override
public void batch(Statement statement) throws SQLException {
//交由delegate处理
delegate.batch(statement);
}
/**
* 用于通知Statement将[insert,update,delete]推送到数据库
* @param statement 执行SQL 语句并返回它所生成结果的对象
* @return 更新记录数
*/
@Override
public int update(Statement statement) throws SQLException {
//交由delegate处理
return delegate.update(statement);
}
/**
* 用于通知Statement将[select]推送到数据库并返回对应查询结果
* @param statement 执行 SQL 语句并返回它所生成结果的对象
* @param resultHandler 结果处理器
* @param 结果对象类型
* @return 结果对象集合
*/
@Override
public List query(Statement statement, ResultHandler resultHandler) throws SQLException {
//交由delegate处理
return delegate.query(statement, resultHandler);
}
/**
* 用于通知Statement将[select]推送到数据库并返回对应游标结果
* @param statement 执行 SQL 语句并返回它所生成结果的对象
* @param 结果对象类型
* @return 结果对象游标对象
* @throws SQLException
*/
@Override
public Cursor queryCursor(Statement statement) throws SQLException {
//交由delegate处理
return delegate.queryCursor(statement);
}
/**
* 获取参数映射与可执行SQL封装类对象
*/
@Override
public BoundSql getBoundSql() {
//交由delegate处理
return delegate.getBoundSql();
}
/**
* 获取参数处理器
*/
@Override
public ParameterHandler getParameterHandler() {
//交由delegate处理
return delegate.getParameterHandler();
}
}
BaseStatementHandler
/**
* Copyright 2009-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.statement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
/**
* 用于简化StatementHandler接口开发的难度,是适配器模式的体现,他有三个实现类:SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler。在RoutingStatementHandler创建时,就根据接受的Excutor来创建这三个类型对象。
* @author Clinton Begin
*/
public abstract class BaseStatementHandler implements StatementHandler {
/**
* mybatis全局配置信息
*/
protected final Configuration configuration;
/**
* 对象工厂
*/
protected final ObjectFactory objectFactory;
/**
* 类型处理注册器,从mybatis全局配置信息中获取
*/
protected final TypeHandlerRegistry typeHandlerRegistry;
/**
* 结果集处理器
*/
protected final ResultSetHandler resultSetHandler;
/**
* 参数处理器
*/
protected final ParameterHandler parameterHandler;
/**
* 执行器
*/
protected final Executor executor;
/**
* Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
*/
protected final MappedStatement mappedStatement;
/**
* Mybatis的分页对象
*/
protected final RowBounds rowBounds;
/**
* 参数映射与可执行SQL封装类对象
*/
protected BoundSql boundSql;
/**
*
* @param executor 执行器
* @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param parameterObject 参数对象
* @param rowBounds Mybatis的分页对象
* @param resultHandler 结果处理器
* @param boundSql 参数映射与可执行SQL封装类对象
*/
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
//调用mappedStatement配置的KeyGenerator,在executor执行boundSQL对象之前,生成Key赋值到parameter中
generateKeys(parameterObject);
//构建boundSQL
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
//构建参数处理器,默认情况下,构建的是DefaultParameteHandler实例
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
//构建结果集处理器,构建出来的是DefaultResultSetHandler实例
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
/**
* 获取参数映射与可执行SQL封装类对象
*/
@Override
public BoundSql getBoundSql() {
return boundSql;
}
/**
* 获取参数处理器
*/
@Override
public ParameterHandler getParameterHandler() {
return parameterHandler;
}
/**
* 创建Statement对象或则PreparedStatment或则CallableStatment
* @param connection 数据库连接对象
* @param transactionTimeout 事务超时时间
* @return 构建出来的Statement实例,已经配置了queryTimeout和fetchSize
*/
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
//设置错误日志上下文
ErrorContext.instance().sql(boundSql.getSql());
//定义一个Statement
Statement statement = null;
try {
//实例化Statement
statement = instantiateStatement(connection);
//设置Statement超时时长
setStatementTimeout(statement, transactionTimeout);
//设置FetchSize:
setFetchSize(statement);
return statement;
} catch (SQLException e) {
//关闭Statment对象
closeStatement(statement);
throw e;
} catch (Exception e) {
//关闭Statment对象
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
/**
* 实例化Statement对象
* @param connection 数据库连接
* @return Statement对象
*/
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
/**
* 设置Statement超时时长
* @param stmt 执行SQL 语句并返回它所生成结果的对象。
* @param transactionTimeout 事务超时时长
*/
protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
//定义查询超时时长变量名
Integer queryTimeout = null;
//如果有配置超时时长
if (mappedStatement.getTimeout() != null) {
//应用配置的超时时长
queryTimeout = mappedStatement.getTimeout();
//如果由配置全局的Statement超时时长
} else if (configuration.getDefaultStatementTimeout() != null) {
//应用全局配置的Statement超时时长
queryTimeout = configuration.getDefaultStatementTimeout();
}
//如果queryTime不为null
if (queryTimeout != null) {
//将queryTime设置到Statement的
stmt.setQueryTimeout(queryTimeout);
}
//应用事务超时。事务超时大于查询时间,则不做更改;否则将查询时间修改成事务时间
StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
}
/**
*
* 设置FetchSize:
*
* 这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动)。
*
*
*
* 假设fetchSize为5,查询总记录数为100,每批5次返回给你,最后结果还是总记录数,只是提高点查询的速度而已
*
*
*
* MySQL不支持fetchSize,默认为一次性取出所有数据。所以容易导致OOM,
* 如果是Oracle的话就是默认取出fetchSize条数据。
* 裸露JDBC防止OOM可以调用statement的enableStreamingResults方法,
* MyBatis应该在<select fetchSize="-2147483648">。
*
* @param stmt 执行SQL 语句并返回它所生成结果的对象。
*/
protected void setFetchSize(Statement stmt) throws SQLException {
//获取select标签的fetchSize属性
Integer fetchSize = mappedStatement.getFetchSize();
//如有设置fetchSize
if (fetchSize != null) {
//设置fetchSize到stmt
stmt.setFetchSize(fetchSize);
return;
}
//获取全局配置的FetchSize
Integer defaultFetchSize = configuration.getDefaultFetchSize();
//如有设置fetchSize
if (defaultFetchSize != null) {
//设置fetchSize到stmt
stmt.setFetchSize(defaultFetchSize);
}
}
/**
* 关闭Statment对象
* @param statement 执行SQL 语句并返回它所生成结果的对象
*/
protected void closeStatement(Statement statement) {
try {
//如果statment不为null
if (statement != null) {
//关闭statment
statement.close();
}
} catch (SQLException e) {
//ignore 忽略关闭时的异常
}
}
/**
* 生成Key
* @param parameter 参数对象
*/
protected void generateKeys(Object parameter) {
//获取配置的Key生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
//保存当前的上下文
ErrorContext.instance().store();
//在executor执行boundSQL对象之前,生成Key赋值到parameter中
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
//恢复当前上下文
ErrorContext.instance().recall();
}
}
CallableStatementHandler
/**
* Copyright 2009-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.statement;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.JdbcType;
/**
* CallableStatement对象处理器,CallableStatmement:用于执行 SQL 存储过程的接口实例
* @author Clinton Begin
*/
public class CallableStatementHandler extends BaseStatementHandler {
/**
*
* @param executor 执行器
* @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param parameter 参数对象
* @param rowBounds Mybatis的分页对象
* @param resultHandler 结果处理器
* @param boundSql 参数映射与可执行SQL封装类对象
*/
public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
/**
* 用于通知Statement将[insert,update,delete]推送到数据库
* @param statement CallableStatement对象
* @return 更新记录数
* @throws SQLException
*/
@Override
public int update(Statement statement) throws SQLException {
//将statement强转成CallableStatement对象
CallableStatement cs = (CallableStatement) statement;
//执行SQL
cs.execute();
//获取更新记录数
int rows = cs.getUpdateCount();
//获取参数对象
Object parameterObject = boundSql.getParameterObject();
//获取Key生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
//执行Key生成器的业务逻辑,将结果赋值到参数对象对应属性中
keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);
/**
* 处理存储过程结果映射,将结果对象赋值到参数对象的属性中(这里的属性是指:参数属性映射配置里配置属性的ParameterType
* 为ParameterMode.OUT或者ParameterMode.INOUT的属性)
*/
resultSetHandler.handleOutputParameters(cs);
return rows;
}
/**
* 将 statement 添加到批处理队列
* @param statement 执行SQL 语句并返回它所生成结果的对象
* @throws SQLException
*/
@Override
public void batch(Statement statement) throws SQLException {
//将statement强转成CallableStatement对象
CallableStatement cs = (CallableStatement) statement;
//添加到批量队列中
cs.addBatch();
}
/**
* 用于通知Statement将[select]推送到数据库并返回对应查询结果
* @param statement CallableStatement对象
* @param resultHandler 结果处理器
* @param 结果对象类型
* @return 结果对象集合
*/
@Override
public List query(Statement statement, ResultHandler resultHandler) throws SQLException {
//将statement强转成CallableStatement对象
CallableStatement cs = (CallableStatement) statement;
//执行SQL
cs.execute();
//处理cs返回所有结果集,返回结果对象集合
List resultList = resultSetHandler.handleResultSets(cs);
/**
* 处理存储过程结果映射,将结果对象赋值到参数对象的属性中(这里的属性是指:参数属性映射配置里配置属性的ParameterType
* 为ParameterMode.OUT或者ParameterMode.INOUT的属性)
*/
resultSetHandler.handleOutputParameters(cs);
return resultList;
}
@Override
public Cursor queryCursor(Statement statement) throws SQLException {
//将statement强转成CallableStatement对象
CallableStatement cs = (CallableStatement) statement;
//执行SQL
cs.execute();
//处理cs返回所有结果集,返回结果对象游标
Cursor resultList = resultSetHandler.handleCursorResultSets(cs);
/**
* 处理存储过程结果映射,将结果对象赋值到参数对象的属性中(这里的属性是指:参数属性映射配置里配置属性的ParameterType
* 为ParameterMode.OUT或者ParameterMode.INOUT的属性)
*/
resultSetHandler.handleOutputParameters(cs);
return resultList;
}
/**
* 实例化Statement对象
* @param connection 数据库连接
* @return
* @throws SQLException
*/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
//获取可执行SQL
String sql = boundSql.getSql();
//mappedStatement对象配置的结果集类型为依赖驱动
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
//创建一个 CallableStatement 对象来调用数据库存储过程。
return connection.prepareCall(sql);
} else {
/**
* ResultSetType.FORWARD_ONLY:结果集的游标只能向下滚动
* ResultSetType.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变
* ResultSetType.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变
*
* ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表。
* ResultSet.CONCUR_UPDATABLE:能用结果集更新数据库中的表
*/
//创建一个 CallableStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。
return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
/**
* 主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改
* @param statement CallableStatement对象
*/
@Override
public void parameterize(Statement statement) throws SQLException {
//注册输出参数到statement
registerOutputParameters((CallableStatement) statement);
//设置参数值到statement
parameterHandler.setParameters((CallableStatement) statement);
}
/**
* 注册输出参数到 {@code cs}
* @param cs 用于执行 SQL 存储过程的接口实例
*/
private void registerOutputParameters(CallableStatement cs) throws SQLException {
//获取参数映射集合
List parameterMappings = boundSql.getParameterMappings();
//遍历参数映射集合
for (int i = 0, n = parameterMappings.size(); i < n; i++) {
//获取参数映射
ParameterMapping parameterMapping = parameterMappings.get(i);
//如果参数映射配置的模式为 输出参数 或者为 输入输出参数
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
//如果参数映射配置jdbc类型为null
if (null == parameterMapping.getJdbcType()) {
//抛出异常
throw new ExecutorException("The JDBC Type must be specified for output parameter. Parameter: " + parameterMapping.getProperty());
} else {
//如果有配置小数点后保留的位数 且 配置的jdbc类型为JdbcType.NUMERIC 或者是 JdbcType.DECIMAL
if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
// 按顺序位置 parameterIndex 将参数注册,设置JDBC类型为JdbcType.NUMERIC 或者 JdbcType.DECIMAL,并设置其小数点后保留的位数
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
} else {
//如果没有配置jdbc类型名
if (parameterMapping.getJdbcTypeName() == null) {
// 按顺序位置 parameterIndex 将参数注册,设置jdbc类型为参数映射所配置的jdbc类型
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);
} else {
// 按顺序位置 parameterIndex 将参数注册,设置jdbc类型为参数映射所配置的jdbc类型,并设置jdbc类型名
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());
}
}
}
}
}
}
}
PreparedStatementHandler
/**
* Copyright 2009-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.statement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
/**
* PreparedStatement对象处理器,PreparedStatement: 预编译的 SQL 语句的对象
* @author Clinton Begin
*/
public class PreparedStatementHandler extends BaseStatementHandler {
/**
*
* @param executor 执行器
* @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param parameter 参数对象
* @param rowBounds Mybatis分页对象
* @param resultHandler 结果处理器
* @param boundSql 参数映射与可执行SQL封装类对象
*/
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
/**
* 用于通知Statement将[insert,update,delete]推送到数据库
* @param statement PreparedStatement对象
* @return 更新记录数
* @throws SQLException
*/
@Override
public int update(Statement statement) throws SQLException {
//将statement强转成PreparedStatment对象
PreparedStatement ps = (PreparedStatement) statement;
//执行SQL
ps.execute();
//获取更新记录数
int rows = ps.getUpdateCount();
//获取参数对象
Object parameterObject = boundSql.getParameterObject();
//获取Key生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
//执行Key生成器的业务逻辑,将结果赋值到参数对象对应属性中
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
/**
* 将{@code statment} 添加到批量队列中
*
* 参考文档:https://www.cnblogs.com/liqiu/p/3825544.html
*
* @param statement PreparedStatement对象
* @throws SQLException
*/
@Override
public void batch(Statement statement) throws SQLException {
//将statement强转成PreparedStatement对象
PreparedStatement ps = (PreparedStatement) statement;
//添加到批量队列中
ps.addBatch();
}
/**
* 用于通知Statement将[select]推送到数据库并返回对应查询结果
* @param statement PreparedStatement对象
* @param resultHandler 结果处理器
* @param 结果对象类型
* @return 结果对象集合
*/
@Override
public List query(Statement statement, ResultHandler resultHandler) throws SQLException {
//将statement强转成PreparedStatement对象
PreparedStatement ps = (PreparedStatement) statement;
//执行SQL
ps.execute();
// 处理 ps 返回所有结果集,返回结果对象集合
return resultSetHandler.handleResultSets(ps);
}
/**
* 用于通知Statement将[select]推送到数据库并返回对应游标结果
* @param statement PreparedStatement对象
* @param 结果对象类型
* @return 结果对象游标
*/
@Override
public Cursor queryCursor(Statement statement) throws SQLException {
//将statement强转成PreparedStatement对象
PreparedStatement ps = (PreparedStatement) statement;
//执行SQL
ps.execute();
//处理stmt返回所有结果集,返回结果对象游标
return resultSetHandler.handleCursorResultSets(ps);
}
/**
* 实例化Statement对象
* @param connection 数据库连接
* @return Statement对象
* @throws SQLException
*/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
//获取可执行的SQL
String sql = boundSql.getSql();
//如果Key生成器是Jdbc3KeyGenerator实例
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
//获取配置的列名
String[] keyColumnNames = mappedStatement.getKeyColumns();
//如果配置的列名为null
if (keyColumnNames == null) {
/**
* PreparedStatement.RETURN_GENERATED_KEYS:使用的是INSERT语句时,可以取出新插入数据行中自动增长的列的值
* PreparedStatement.NO_GENERATED_KEYS:不会取出新插入数据行中自动增长的列的值
*/
//创建一个默认 PreparedStatement 对象,该对象能获取自动生成的键
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
//创建一个能返回由keyColumnNames指定的自动生成键的默认 PreparedStatement 对象
return connection.prepareStatement(sql, keyColumnNames);
}
//mappedStatement对象配置的结果集类型为依赖驱动
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
//创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。
return connection.prepareStatement(sql);
} else {
/**
* ResultSetType.FORWARD_ONLY:结果集的游标只能向下滚动
* ResultSetType.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变
* ResultSetType.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变
*
* ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表。
* ResultSet.CONCUR_UPDATABLE:能用结果集更新数据库中的表
*/
//创建一个 PreparedStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
/**
* 主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改
* @param statement PreparedStatement对象
*/
@Override
public void parameterize(Statement statement) throws SQLException {
//将参数对象赋值到statement中
parameterHandler.setParameters((PreparedStatement) statement);
}
}
SimpleStatementHandler
/**
* Copyright 2009-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.statement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
/**
* 简单的Statement处理器,Statement:用于执行静态 SQL 语句并返回它所生成结果的对象
* @author Clinton Begin
*/
public class SimpleStatementHandler extends BaseStatementHandler {
/**
*
* @param executor 执行器
* @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param parameter 参数对象
* @param rowBounds Mybatis的分页对象
* @param resultHandler 结果处理器
* @param boundSql 参数映射与可执行SQL封装类对象
*/
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 {
//获取SQL脚本
String sql = boundSql.getSql();
//获取参数对象
Object parameterObject = boundSql.getParameterObject();
//获取Key生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
//已更新的函数
int rows;
if (keyGenerator instanceof Jdbc3KeyGenerator) {
//PreparedStatement.RETURN_GENERATED_KEYS:获取刚刚插入自增ID值
//执行SQL
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
//获取更新记录数
rows = statement.getUpdateCount();
//Keys生成器将更新之后主键信息赋值到参数对象对应的属性中
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
//执行SQL
statement.execute(sql);
//获取更新记录数
rows = statement.getUpdateCount();
//Keys生成器执行DML标签中的selectKey标签的SQL脚本,并将结果赋值到参数对象对应的属性中
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
//执行SQL
statement.execute(sql);
//获取更新记录数
rows = statement.getUpdateCount();
}
return rows;
}
/**
* 批处理,只是获取boundSql的可执行SQL,然后添加到 {@code statment}
* @param statement 执行 SQL 语句并返回它所生成结果的对象
*/
@Override
public void batch(Statement statement) throws SQLException {
//获取可执行SQL
String sql = boundSql.getSql();
//添加批处理队列中
statement.addBatch(sql);
}
/**
* 用于通知Statement将[select]推送到数据库并返回对应查询结果
* @param statement 执行 SQL 语句并返回它所生成结果的对象
* @param resultHandler 结果处理器
* @param 结果对象类型
* @return
*/
@Override
public List query(Statement statement, ResultHandler resultHandler) throws SQLException {
//获取可执行SQL
String sql = boundSql.getSql();
//执行SQL
statement.execute(sql);
//处理 statement 中的所有结果集,返回结果对象集合
return resultSetHandler.handleResultSets(statement);
}
/**
* 用于通知Statement将[select]推送到数据库并返回对应游标结果
* @param statement 执行 SQL 语句并返回它所生成结果的对象
* @param 结果对象类型
* @return 结果对象游标对象
*/
@Override
public Cursor queryCursor(Statement statement) throws SQLException {
//获取可执行SQL
String sql = boundSql.getSql();
//执行SQL
statement.execute(sql);
//处理statement 中的所有结果集,返回结果对象游标
return resultSetHandler.handleCursorResultSets(statement);
}
/**
* 实例化Statment对象
* @param connection 数据库连接
* @return 执行 SQL 语句并返回它所生成结果的对象
*/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
//ResultSetType.DEFAULT:表示依赖驱动进行创建Statement实例
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
//创建一个 Statement 对象来将 SQL 语句发送到数据库
return connection.createStatement();
} else {
/**
* ResultSetType.FORWARD_ONLY:结果集的游标只能向下滚动
* ResultSetType.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变
* ResultSetType.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变
*
* ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表。
* ResultSet.CONCUR_UPDATABLE:能用结果集更新数据库中的表
*/
//创建一个 Statement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
@Override
public void parameterize(Statement statement) {
// N/A N/A是Not Applicable 的缩写,表示“不适用”的意思
}
}