MyBatis-statement模块
MYBATIS-statement模块
概述
StatementHandler负责处理Mybatis与JDBC之间Statement的交互,而JDBC中的Statement,我们在学习JDBC的时候就了解过,就是负责与数据库进行交互的对象。这其中会涉及到一些对象,我们用到的时候再学习。首先,我们来看下StatementHandler的体系结构。
StatementHandler接口
statementHandler接口的实现大致有四个,其中三个实现类都是和JDBC中的Statement响对应的:
- SimpleStatementHandler,这个很简单了,就是对应我们JDBC中常用的Statement接口,用于简单SQL的处理;
- PreparedStatementHandler,这个对应JDBC中的PreparedStatement,预编译SQL的接口;
- CallableStatementHandler,这个对应JDBC中CallableStatement,用于执行存储过程相关的接口;
- RoutingStatementHandler,这个接口是以上三个接口的路由,没有实际操作,只是负责上面三个StatementHandler的创建及调用。
/**
* @author Clinton Begin
*/
public interface StatementHandler {
/**
* 从connection中获取statement
*
* @param connection
* @param transactionTimeout
* @return
* @throws SQLException
*/
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
/**
* sql参数设置
*
* @param statement
* @throws SQLException
*/
void parameterize(Statement statement)
throws SQLException;
/**
* 批量执行
*
* @param statement
* @throws SQLException
*/
void batch(Statement statement)
throws SQLException;
/**
* 更新
*
* @param statement
* @return
* @throws SQLException
*/
int update(Statement statement)
throws SQLException;
/**
* 查询
*
* @param statement
* @param resultHandler
* @param <E>
* @return
* @throws SQLException
*/
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
/**
* 游标查询
*
* @param statement
* @param <E>
* @return
* @throws SQLException
*/
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
/*
获取BoundSql
*/
BoundSql getBoundSql();
/**
* 获取参数处理器
*
* @return
*/
ParameterHandler getParameterHandler();
}
RoutingStatementHandler
RoutingStatementHandler类似路由器,在其构造函数中会根据Mapper文件中设置的StatementType来选择使用SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler,其实现的接口StatementHandler的方法也是由这三个具体实现类来实现。
/**
* 路由Statement处理器
* 装饰器模式
*
* @author Clinton Begin
*/
public class RoutingStatementHandler implements StatementHandler {
/**
* 装饰器的StatementHandler
*/
private final StatementHandler delegate;
/**
* 构造方法
* 选择三种Statement,SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler
*
* @param executor
* @param ms
* @param parameter
* @param rowBounds
* @param resultHandler
* @param boundSql
*/
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据Statement类型选择不同的处理器
switch (ms.getStatementType()) {
//STATEMENT类型
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());
}
}
/**
* 执行具体类型prepare
*
* @param connection
* @param transactionTimeout
* @return
* @throws SQLException
*/
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
return delegate.prepare(connection, transactionTimeout);
}
@Override
public void parameterize(Statement statement) throws SQLException {
delegate.parameterize(statement);
}
@Override
public void batch(Statement statement) throws SQLException {
delegate.batch(statement);
}
@Override
public int update(Statement statement) throws SQLException {
return delegate.update(statement);
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
return delegate.query(statement, resultHandler);
}
@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
return delegate.queryCursor(statement);
}
@Override
public BoundSql getBoundSql() {
return delegate.getBoundSql();
}
@Override
public ParameterHandler getParameterHandler() {
return delegate.getParameterHandler();
}
}
BaseStatementHandler类
BaseStatementHandler是一个抽象类,并没有实现和CURD相关的类,只是更多的设置了一些参数相关。
/**
* @author Clinton Begin
*/
public abstract class BaseStatementHandler implements StatementHandler {
//配置信息
protected final Configuration configuration;
//对象工厂
protected final ObjectFactory objectFactory;
//类型处理器注册
protected final TypeHandlerRegistry typeHandlerRegistry;
//结果集处理
protected final ResultSetHandler resultSetHandler;
//参数处理器
protected final ParameterHandler parameterHandler;
//执行器
protected final Executor executor;
protected final MappedStatement mappedStatement;
protected final RowBounds rowBounds;
protected BoundSql boundSql;
/**
* 构造方法
*
* @param executor
* @param mappedStatement
* @param parameterObject
* @param rowBounds
* @param resultHandler
* @param boundSql
*/
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();
//处理sql之前生成key
if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
//创建参数处理器
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
//创建结果集处理器
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
/**
* 获取boundSql
*
* @return
*/
@Override
public BoundSql getBoundSql() {
return boundSql;
}
/**
* 获取参数处理器
*
* @return
*/
@Override
public ParameterHandler getParameterHandler() {
return parameterHandler;
}
/**
* 从连接中获取Statement对象
*
* @param connection
* @param transactionTimeout
* @return
* @throws SQLException
*/
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
statement = instantiateStatement(connection);
//设置超时时间
setStatementTimeout(statement, transactionTimeout);
//设置读取条数,其实就是调用Statement.setFetchSize
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);
}
}
/**
* 如何实例化Statement,交给子类去做
* @param connection
* @return
* @throws SQLException
*/
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
/**
* 设置超时,实际就是调用Statement.setQueryTimeout
*
* @param stmt
* @param transactionTimeout
* @throws SQLException
*/
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);
}
/**
* 设置读取条数,其实就是调用Statement.setFetchSize
*
* @param stmt
* @throws SQLException
*/
protected void setFetchSize(Statement stmt) throws SQLException {
Integer fetchSize = mappedStatement.getFetchSize();
if (fetchSize != null) {
stmt.setFetchSize(fetchSize);
return;
}
Integer defaultFetchSize = configuration.getDefaultFetchSize();
if (defaultFetchSize != null) {
stmt.setFetchSize(defaultFetchSize);
}
}
/**
* 关闭Statement
*
* @param statement
*/
protected void closeStatement(Statement statement) {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException e) {
//ignore
}
}
/**
* 生成主键
*
* @param parameter
*/
protected void generateKeys(Object parameter) {
//获取主键生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
ErrorContext.instance().store();
//生成主键
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
ErrorContext.instance().recall();
}
}
SimpleStatementHandler类
SimpleStatementHandler就是使用基本的Statement来执行query、batch、update等操作,其实现还是比较简单的,当然在执行过程中会涉及keyGenerator和ResultHandler操作。SimpleStatementHandler用于执行简单的sql语句,这里简单的sql语句是指sql语句中没有变量,不会通过外部进行参数传入的sql语句。
/**
* 简单Statement处理器
*
* @author Clinton Begin
*/
public class SimpleStatementHandler extends BaseStatementHandler {
/**
* 构造方法
*
* @param executor
* @param mappedStatement
* @param parameter
* @param rowBounds
* @param resultHandler
* @param boundSql
*/
public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
/**
* 更新操作
*
* @param statement
* @return
* @throws SQLException
*/
@Override
public int update(Statement statement) throws SQLException {
//获取sql
String sql = boundSql.getSql();
//获取参数
Object parameterObject = boundSql.getParameterObject();
//获取主键生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
//操作行数
int rows;
//
if (keyGenerator instanceof Jdbc3KeyGenerator) {
//执行sql
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
//获取更新条数
rows = statement.getUpdateCount();
//获取执行后的主键
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
//执行sql
statement.execute(sql);
//获取执行行数
rows = statement.getUpdateCount();
//获取执行后的主键
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
//如果没有keyGenerator,直接调用Statement.execute和Statement.getUpdateCount
statement.execute(sql);
rows = statement.getUpdateCount();
}
return rows;
}
/**
* 批量sql执行
*
* @param statement
* @throws SQLException
*/
@Override
public void batch(Statement statement) throws SQLException {
//获取sql
String sql = boundSql.getSql();
//添加批处理sql
statement.addBatch(sql);
}
/**
* 查询
* @param statement
* @param resultHandler
* @param <E>
* @return
* @throws SQLException
*/
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
//获取sql
String sql = boundSql.getSql();
//执行sql
statement.execute(sql);
//由结果处理器来处理结果
return resultSetHandler.handleResultSets(statement);
}
/**
* 游标查询
* @param statement
* @param <E>
* @return
* @throws SQLException
*/
@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
//获取sql
String sql = boundSql.getSql();
//执行sql
statement.execute(sql);
//由结果集处理器处理游标数据
return resultSetHandler.handleCursorResultSets(statement);
}
/**
* 实例化Statement实现
* @param connection
* @return
* @throws SQLException
*/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
//如果是默认的结果集
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
//直接创建Statement
return connection.createStatement();
} else {
//其他情况创建具体类型的Statement
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
/**
* 简单处理器不处理参数
* @param statement
*/
@Override
public void parameterize(Statement statement) {
// N/A
}
}
PreparedStatementHandler类
PreparedStatementHandler就是调用PreparedStatement来执行SQL语句,这样在第一次执行sql语句时会进行预编译,在接下来执行相同的SQL语句时会提高数据库性能
/**
* 预处理Statement处理器
*
* @author Clinton Begin
*/
public class PreparedStatementHandler extends BaseStatementHandler {
/**
* 构造方法
*
* @param executor
* @param mappedStatement
* @param parameter
* @param rowBounds
* @param resultHandler
* @param boundSql
*/
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
/**
* 更新操作
*
* @param statement
* @return
* @throws SQLException
*/
@Override
public int update(Statement statement) throws SQLException {
//转换成预编译的PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
//执行
ps.execute();
//获取执行行数
int rows = ps.getUpdateCount();
//获取参数
Object parameterObject = boundSql.getParameterObject();
//获取主键生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
//设置主键
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
/**
* 批量处理
*
* @param statement
* @throws SQLException
*/
@Override
public void batch(Statement statement) throws SQLException {
//转换成预编译的PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
//添加到批处理
ps.addBatch();
}
/**
* 查询操作
*
* @param statement
* @param resultHandler
* @param <E>
* @return
* @throws SQLException
*/
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
//转换成预编译的PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
//执行查询
ps.execute();
//交给结果集处理器处理
return resultSetHandler.handleResultSets(ps);
}
//游标查询
@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
//转换成预编译的PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
//执行查询
ps.execute();
//交给结果集处理器处理
return resultSetHandler.handleCursorResultSets(ps);
}
/**
* 实例化Statement
*
* @param connection
* @return
* @throws SQLException
*/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
//获取sql
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
//获取key的数组
String[] keyColumnNames = mappedStatement.getKeyColumns();
//没有key就直接创建prepareStatement
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
//其他情况创建带有列明的prepareStatement
return connection.prepareStatement(sql, keyColumnNames);
}
//如果结果集类型是默认的
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
//直接创建prepareStatement
return connection.prepareStatement(sql);
} else {
//其他情况根据类型创建prepareStatement
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
/**
* 参数处理器处理参数
*
* @param statement
* @throws SQLException
*/
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
CallableStatementHandler
CallableStatementHandler实际就是使用CallableStatement来执行SQL语句,当然它执行的是存储过程。
/**
* 存储过程处理器
* @author Clinton Begin
*/
public class CallableStatementHandler extends BaseStatementHandler {
/**
* 构造方法
* @param executor
* @param mappedStatement
* @param parameter
* @param rowBounds
* @param resultHandler
* @param boundSql
*/
public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
/**
* 更新操作
* @param statement
* @return
* @throws SQLException
*/
@Override
public int update(Statement statement) throws SQLException {
//将statement转换为CallableStatement
CallableStatement cs = (CallableStatement) statement;
//执行execute操作
cs.execute();
//获取更新行数
int rows = cs.getUpdateCount();
//获取参数
Object parameterObject = boundSql.getParameterObject();
//获取主键生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
//设置主键
keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);
//结果集进行处理
resultSetHandler.handleOutputParameters(cs);
return rows;
}
/**
* 批量处理
* @param statement
* @throws SQLException
*/
@Override
public void batch(Statement statement) throws SQLException {
//将statement转换为CallableStatement
CallableStatement cs = (CallableStatement) statement;
//添加到批处理
cs.addBatch();
}
/**
* 查询操作
* @param statement
* @param resultHandler
* @param <E>
* @return
* @throws SQLException
*/
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
//将statement转换为CallableStatement
CallableStatement cs = (CallableStatement) statement;
//执行查询
cs.execute();
//通过结果集处理器处理结果
List<E> resultList = resultSetHandler.handleResultSets(cs);
//处理参数
resultSetHandler.handleOutputParameters(cs);
return resultList;
}
/**
* 游标查询
* @param statement
* @param <E>
* @return
* @throws SQLException
*/
@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
//将statement转换为CallableStatement
CallableStatement cs = (CallableStatement) statement;
//执行execute操作
cs.execute();
//结果集处理器处理游标数据
Cursor<E> resultList = resultSetHandler.handleCursorResultSets(cs);
//处理输出参数
resultSetHandler.handleOutputParameters(cs);
return resultList;
}
/**
* 实例化Statement
* @param connection
* @return
* @throws SQLException
*/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
//获取sql
String sql = boundSql.getSql();
//如果是默认的结果集处理器
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
//创建存储过程Statement
return connection.prepareCall(sql);
} else {
//其他情况根据结果集类型创建存储过程Statement
return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
/**
* 参数设置
* @param statement
* @throws SQLException
*/
@Override
public void parameterize(Statement statement) throws SQLException {
//注册输出参数
registerOutputParameters((CallableStatement) statement);
//参数处理器设置参数
parameterHandler.setParameters((CallableStatement) statement);
}
/**
* 注册输出参数
* @param cs
* @throws SQLException
*/
private void registerOutputParameters(CallableStatement cs) throws SQLException {
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
for (int i = 0, n = parameterMappings.size(); i < n; i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
//处理存储过程的INOUT和OUT
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
if (null == parameterMapping.getJdbcType()) {
throw new ExecutorException("The JDBC Type must be specified for output parameter. Parameter: " + parameterMapping.getProperty());
} else {
if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
} else {
if (parameterMapping.getJdbcTypeName() == null) {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);
} else {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());
}
}
}
}
}
}
}