ResultHandler
前面说过,StatmentHandler
最后在处理查询结果的时候,会调用ResultSetHandler
处理结果,在看完ResultSetHandler
之后,本来想分析一下它的代码,但是存在两个问题:
- 由于涉及到各种业务逻辑,比如
<association>
等,导致代码比较复杂 - 结果中都是中规中矩的处理
因此,便不一一分析其代码。这里,我们说一说MyBatis
中的ResultHandler
在MyBatis
Java API
中,对于Select
可以指定一个ResultHandler
来自行处理结果:
@Override
public void select(String statement, Object parameter, ResultHandler handler) {
select(statement, parameter, RowBounds.DEFAULT, handler);
}
而对于MyBatis
的Mapper
,我们只需要在参数中添加ResultHandler
,MyBatis
便自己会使用该ResultHandler
处理结果。
public interface ResultHandler<T> {
void handleResult(ResultContext<? extends T> resultContext);
}
ResultHandler
只有一个方法,处理结果,参数是ResultContext
。
public interface ResultContext<T> {
//获取结果对象
T getResultObject();
//获取结果对象已经加载的数量
int getResultCount();
//是否已经停止加载
boolean isStopped();
//停止获取数据
void stop();
}
可以看到,通过ResultContext
,我们可以定制化设置一些数据。
使用ResultHandler
有以下两点限制:
- 方法的返回值为
void
,因为通过定制的ResultHandler
,MyBaits
不会再后续继续处理数据 - 方法的参数需要带有
ResultHander
以上限制从以下代码可以看出来:
case SELECT:
//如果方法返回为空 并且 带有ResultHandler参数
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
而默认的DefaultResultHandler
仅仅 是将结果放在List
中,然后返回:
public class DefaultResultHandler implements ResultHandler<Object> {
private final List<Object> list;
public DefaultResultHandler() {
list = new ArrayList<>();
}
@SuppressWarnings("unchecked")
public DefaultResultHandler(ObjectFactory objectFactory) {
list = objectFactory.create(List.class);
}
@Override
public void handleResult(ResultContext<?> context) {
list.add(context.getResultObject());
}
public List<Object> getResultList() {
return list;
}
}
在MyBatis
官网提示到,如果使用了ResultHandler
处理结果,那么结果不会被缓存,这里需要注意。
明白了ResultHandler
,就可以看ResultSetHandler
了。
public interface ResultSetHandler {
//处理结果
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
//处理游标结果
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
//处理存储过程返回的结果
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
这个接口的所有方法都是输入Statment
,输出处理完成的结果,其内部是调用的statement#getResultSet()
实现。
需要明白的是,在调用此方法之前,MyBatis
已经执行了Statment#Query()
方法。
总结一句话,ResultSetHandler
便是用来处理查询结果的,ResultHandler
是用来处理每行的结果。