第四步 也是最后一步的分析:mapper.getDepartmentById(1)
因为mapper是动态代理对象,执行getDepartmentById(1)方法时由动态代理执行,调用debug进入invoke方法
代码如下
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {// #1
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);// #2
}
代码#1
处,先判断是否是属于Object的类的方法,如果是,那么直接返回调用。
然后执行到 代码#2
处,进入这个mapperMethod.execute(sqlSession, args)
方法。
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
/*根据其command.getType()返回对应的结果集*/
switch (command.getType()) { // #1
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT: // #2
if (method.returnsVoid() && method.hasResultHandler()) { // #3
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args); // #4
result = sqlSession.selectOne(command.getName(), param); // #5
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
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;
}
代码#·1
根据sql语句查询的类型,执行对应的操作,这里的command.getType()=SELECT
执行代码2
case SELECT: // #2
if (method.returnsVoid() && method.hasResultHandler()) { // #3
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) { //返回结果是多个
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) { //返回结果集合是map
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) { //返回结果集合是光标
result = executeForCursor(sqlSession, args);
} else {//我这里的查询语句是查询单个对象,所以执行这里。
Object param = method.convertArgsToSqlCommandParam(args); // #4
result = sqlSession.selectOne(command.getName(), param); // #5
}
代码#4处method.convertArgsToSqlCommandParam(args)这个方法的作用是用来解析参数的,将参数sql里面的参数类型
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);
}
getNamedParams(args) 代码如下:
public Object getNamedParams(Object[] args) {
//(@param stirng username ,@param int age , String hight )
//names是什么?是SortedMap<Integer, String> names 跟我们传入的参数的name构造出一个map{0=username,1=age,2=2} ,names的构造过程,再下一段代码
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
final Map<String, Object> param = new ParamMap<Object>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
//有两种构造的方法{0=username,1=age,2=2}
//第一种{username=arg[0],age=arg[1],2=arg[2]}
param.put(entry.getValue(), args[entry.getKey()]);
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// ensure not to overwrite parameter named with @Param
if (!names.containsValue(genericParamName)) {
// 第二种:{param1=arg[0],param2=arg[1],param3=arg[3]}
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
}
names的构造过程入下
public ParamNameResolver(Configuration config, Method method) {
//获得参数类型
final Class<?>[] paramTypes = method.getParameterTypes();
// 获得参数注解
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
//构造一个map
final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
int paramCount = paramAnnotations.length;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
// skip special parameters
continue;
}
String name = null;
// 如果带有注解标识的 name=((Param) annotation).value(); 例如:@param String username,此时的name=username
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// 如果是全局配置,那么 :name=参数名
if (config.isUseActualParamName()) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// 没有标注,那么相当于name=(map.size()) 当前索引的位置{0=name,1=age,2=2}
//
name = String.valueOf(map.size());
}
}
//添加到map当中
map.put(paramIndex, name);
}
入参数被解析成map集合然后返回,执行 result = sqlSession.selectOne(command.getName(), param);
/*selectOne(command.getName(), param)*/
@Override
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(statement, parameter)
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//statement为存储在map集合当中的key:com.kuake.dao.mapper.DepartmentMapper.getDepartmentById
//通过key拿到MappedStatement 对象
MappedStatement ms = configuration.getMappedStatement(statement);
//调用query方法,执行语句。
// wrapCollection(parameter)对出入的参数进行包装,
/*
if (object instanceof Collection) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("array", object);
return map;
}
return object;
*/
将传入的参数进行包装成map List的key list collection的key collection Array的key array
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
执行query()方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//返回boundSql ,也就是sql语句的详细信息 下面的截图可以看到详细信息
BoundSql boundSql = ms.getBoundSql(parameterObject);
//创建一个缓存的key
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
query方法的调用,
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 因为没有开启缓存 ,调用配置了的SimpleExector
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
** delegate. query()先从本地缓存当中获得,如果为空调用queryFromDatabase()**
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
//先从本地缓存当中获得,如果为空调用queryFromDatabase()
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
** queryFromDatabase(xxx,xxx,xxx,xxx)方法如下**
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
//在本地一级缓存当中设置一个占位符
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
//执行次方法
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
//查询到结果之后,把他存入本地缓存,一级缓存当中
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
执行doQuery()
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
// 这个Statement 是我们jdbc原生的Statement
Statement stmt = null;
try {
//从MappedStatement 对象当中获得configuration
Configuration configuration = ms.getConfiguration();
//创建一个newStatementHandler,1同时也会构造parameterHandler,ResultSetHandler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
} finally {
// 关闭资源
closeStatement(stmt);
}
}
** configuration.newStatementHandler()创建一个StatementHandler用于创建Statement **
创建原生jdbc的statement的prepareStatement(handler, ms.getStatementLog()) 代码如下:
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
//创建Statement 对象的时候
stmt = handler.prepare(connection, transaction.getTimeout());
//进行参数预编译TypeHandler typeHandler = parameterMapping.getTypeHandler();设置参数。
handler.parameterize(stmt);
return stmt;
}
**执行handler.query(stmt, resultHandler)**方法拿到返回结果。
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
//执行查询
ps.execute();
//使用resultSetHandler来解析设置查询结果
return resultSetHandler.<E> handleResultSets(ps);
}
其调用过程的时序图如下图所示:
小结一下:四大对象
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed):执行器
ParameterHandler (getParameterObject, setParameters):设置预编译参数用的
ResultSetHandler (handleResultSets, handleOutputParameters):处理结果集
StatementHandler (prepare, parameterize, batch, update, query) :处理sql语句预编译,设置参数等相关工作;
执行过程: