您的位置:首页 > 数据库

Mybatis实现【4】-查询解析(一次SQL查询的源码分析)

2014-06-18 16:29 791 查看
执行流程图:


 

一、在Service层调用Mapper Interface中的方法实现对数据库的操作

二、MapperProxy将拦截所有调用数据库的操作,所以实际上调用的是MapperProxy中的方法。

//当调用Mapper的方法时,实际上将由MapperProxy中的invoke方法处理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
//获取MapperMethod类
final MapperMethod mapperMethod = cachedMapperMethod(method);
//执行MapperMethod,并返回结果
return mapperMethod.execute(sqlSession, args);
}
//从缓存中或则实例化一个MapperMethod类,用于处理数据库操作
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}

三、MapperMethod的execute方法如下:

public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
if (SqlCommandType.INSERT == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
} else if (SqlCommandType.UPDATE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
} else if (SqlCommandType.DELETE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
} else if (SqlCommandType.SELECT == command.getType()) {
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else {
//图示调用的是selectOne
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
} else {
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}

四、前面中MyBatis返回给应用的DefaultSqlSession。

DefaultSqlSession里面有各种各样的SQL执行方法,主要用于SQL操作的对外接口,它会调用执行器执行实际的SQL语句。

1、selectOne方法

public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.<T>selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}

它实际上调用selectList方法。该方法如下:

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//根据SQL的ID到配置信息中找对应的MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
//调用执行器的query方法
List<E> result = executor.<E>query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
return result;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

2、执行器执行过程

2.1、默认使用的SimpleExecutor。根据调用链,最终执行的是SimpleExecutor的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();
//new一个StatementHandler对象,该类主要用于处理一次SQL操作
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);
//预处理StatementHandler对象,得到Statement对象
stmt = prepareStatement(handler, ms.getStatementLog());
//执行sql,并对执行结果进行处理
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}

2.2、StatementHandler

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 = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}

2.2.1、RoutingStatementHandler

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据MappedStatement对象的statementType来创建不同的StatementHandler。StatementType有STATEMENT、PREPARED和CALLABLE三种类型,和JDBC类型对应
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());
}

}

2.3、prepareStatement方法具体内容

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
//从链接中获取Statement对象
stmt = handler.prepare(connection);
//处理预编译的传入对象
handler.parameterize(stmt);
return stmt;
}


该系列文章参考如下书籍及文章:

《Java Persistence with MyBatis 》

《http://www.cnblogs.com/hzhuxin/p/3349836.html》

《http://www.iteye.com/topic/1112327》

《http://www.iteye.com/blogs/subjects/mybatis_internals》

《http://denger.me/2011/05/mybatis-and-spring-interface-integrated/》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: