这一篇我们来梳理Mybatis中的StatementHandler接口及其对应的实现类。
这个接口处理的是java JDBC对应的Statement,可以先搜索其他博文复习下关于JDBC的内容。
一、StatementHandler的结构
public interface StatementHandler {
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
void parameterize(Statement statement)
throws SQLException;
void batch(Statement statement)
throws SQLException;
int update(Statement statement)
throws SQLException;
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
BoundSql getBoundSql();
ParameterHandler getParameterHandler();
}
可以看到这里抽象定义了对Statement一些操作的方法。
2、方法
1)、prepare(Connection connection, Integer transactionTimeout)
这个方法就是通过sql连接及对应的事务超时时间创建对应的JDB语句处理的Statement对象。
2、parameterize(Statement statement)
对入参进行对应的处理
3、batch(Statement statement)
批量操作接口。
4、update(Statement statement)
更新操作。
5、query(Statement statement, ResultHandler resultHandler)
查询接口,这里的其中一个入参ResultHandler 是表明用来处理查询结果的。
6、queryCursor(Statement statement)
这个接口是用来处理调用处理存储过程的,我们之后也会忽略关于存储过程的一些细节内容。
7、getBoundSql()
这个是获取BoundSql,这个BoundSql是与sql语句执行的一些内容,前面文章有介绍。
8、getParameterHandler()
获取参数处理器。
下面我们来看下StatementHandler的实现类。
二、BaseStatementHandler
1、结构
public abstract class BaseStatementHandler implements StatementHandler {
这个是StatementHandler接口实现的基类,可以看到其只是简单的实现了StatementHandler接口。
2、成员变量
1)、configuration
protected final Configuration configuration;
这个类我们在前面文章有梳理,其包含了整个Mybatis中加载的内容,有点类似于Spring容器中存放对象的类 DefaultListableBeanFactory。
2)、objectFactory
protected final ObjectFactory objectFactory;
创建对象的工厂。
3)、typeHandlerRegistry
protected final TypeHandlerRegistry typeHandlerRegistry;
类型转换处理器,在前面文章也有对应的分析,例如可以通过在xml写的类型例如javaType,jdbcType来处理对应的值。
4)、resultSetHandler
protected final ResultSetHandler resultSetHandler;
public interface ResultSetHandler {
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
结构集处理器,用来处理执行查询语句后的ResultSet内容的。
5)、parameterHandler
protected final ParameterHandler parameterHandler;
public interface ParameterHandler {
Object getParameterObject();
void setParameters(PreparedStatement ps)
throws SQLException;
}
参数处理器,用来设置获取对应参数的。
6)、executor
protected final Executor executor;
执行器,这个我们之后再梳理这个接口及其实现。
7)、mappedStatement
protected final MappedStatement mappedStatement;
这个类我们前面也有了解,其包含Mapper接口中方法执行相关的内容。例如用来查询方法,这个MappedStatement就包含要执行这个方法的内容,例如sql、执行类型等各种信息。
8)、rowBounds
protected final RowBounds rowBounds;
public class RowBounds {
public static final int NO_ROW_OFFSET = 0;
public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
public static final RowBounds DEFAULT = new RowBounds();
分页用的,例如limit NO_ROW_OFFSET NO_ROW_LIMIT。
9)、boundSql
protected BoundSql boundSql;
sql语句相关内容。
3、构造方法
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
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);
}
这个就是创建时候对对应变量的初始化赋值。
1)、newParameterHandler(…)
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
}
可以看到ParameterHandler是直接使用的默认参数处理器DefaultParameterHandler。但这里需要注意的是,在DefaultParameterHandler创建后,还会将其去执行Interceptor(所以就可以在这里去进行对应的拓展,例如去实现Interceptor接口创建一个自定义的ParameterHandler)。
2)、 newResultSetHandler(…)
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
这个一前面类似,也是使用的默认结果集处理器DefaultResultSetHandler,然后也会执行pluginAll方法。
3、主要方法
1)、prepare(Connection connection, Integer transactionTimeout)
@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);
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 abstract Statement instantiateStatement(Connection connection) throws SQLException;
创建Statement,再设置其的超时时间、fetchSize。不过这里的创建Statement是一个抽象方法需要其的子类实现。
三、SimpleStatementHandler
这个就是简单语句处理器,基于Statement去操作。
1、结构&构造方法
public class SimpleStatementHandler extends BaseStatementHandler {
public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
继于BaseStatementHandler,然后构造方法直接调用的父类BaseStatementHandler。
2、方法
1)、update(Statement statement)
@Override
public int update(Statement statement) throws SQLException {
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
int rows;
if (keyGenerator instanceof Jdbc3KeyGenerator) {
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
statement.execute(sql);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
statement.execute(sql);
rows = statement.getUpdateCount();
}
return rows;
}
这个就是执行对应的更新sql,我们忽略这里与keyGenerator相关的内容,其主要是两条语句,通过statement.execute(sql)执行对应的sql,然后在通过getUpdateCount方法获取本次受影响的行数再返回。
2)、batch(Statement statement)
@Override
public void batch(Statement statement) throws SQLException {
String sql = boundSql.getSql();
statement.addBatch(sql);
}
批处理方法,直接调用的statement.addBatch(sql)。
3)、query(Statement statement, ResultHandler resultHandler)
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.handleResultSets(statement);
}
查询方法,其会通过ResultHandler去处理对应的ResultSet结果集。
4)、queryCursor(Statement statement)
@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.handleCursorResultSets(statement);
}
这个是处理存储过程。
5)、instantiateStatement(Connection connection)
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.createStatement();
} else {
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
可以看到这里对Statement创建是不同的,如果是ResultSetType.DEFAULT,则直接创建。但如果是其他的,其会再这里设置对应的结果集遍历对应的操作。
6)、parameterize(Statement statement)
@Override
public void parameterize(Statement statement) {
// N/A
}
没有操作。
四、PreparedStatementHandler
这个StatementHandler是基于PreparedStatement去进行对应的操作
1、结构&构造方法
public class PreparedStatementHandler extends BaseStatementHandler {
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
与前面的SimpleStatementHandler一样。
2、方法
1)、update(Statement statement)
@Override
public int update(Statement statement) throws SQLException {
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;
}
这里也是ps.execute()、ps.getUpdateCount()的执行,不过不同点是这里使用的PreparedStatement。
2)、batch(Statement statement)
@Override
public void batch(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.addBatch();
}
3)、query(Statement statement, ResultHandler resultHandler)
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleResultSets(ps);
}
查询再通过ResultHandler去处理对应的结果。
4)、queryCursor(Statement statement)
@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleCursorResultSets(ps);
}
存储过程相关执行。
5)、instantiateStatement(Connection connection)
@Override
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) {
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
这里就是创建PrepareStatement,以及设置对应的结果遍历的行为。
6)、parameterize(Statement statement)
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
这里与前面SimpleStatementHandler不同的是其会去调用parameterHandler.setParameters((PreparedStatement) statement)去设置对应参数。