源码分析
在dao调用查询数据库的方法上打上断点后,点击 step into 就会进入到动态代理生成的 MapperProxy 类中
java
// MapperProxy.class 执行invoke 方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 是不是Object类,很明显我们传递过来的类不是,谁调用的这个方法 类就是谁
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
// 真正执行
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
try {
return MapUtil.computeIfAbsent(methodCache, method, m -> {
// 是不是默认方法 接口可以有default方法
if (m.isDefault()) {
try {
if (privateLookupInMethod == null) {
return new DefaultMethodInvoker(getMethodHandleJava8(method));
} else {
return new DefaultMethodInvoker(getMethodHandleJava9(method));
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException
| NoSuchMethodException e) {
throw new RuntimeException(e);
}
} else {
// 普通的
return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
});
} catch (RuntimeException re) {
Throwable cause = re.getCause();
throw cause == null ? re : cause;
}
}
// MapperMethod.class
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
创建 MapperMethod 的时候就已经在构造方法中对一些属性赋过值了。
然后通过上一步拿到的 MapperMethodInvoker 调用 invoke() :
java
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
return mapperMethod.execute(sqlSession, args);
}
再通过 MapperMethod 调用 execute() 真正执行:
java
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
// insert语句
case INSERT: {
// 参数解析器
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
// update语句
case UPDATE: {
// 参数解析器
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
// delete语句
case DELETE: {
// 参数解析器
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
// select语句
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
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);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
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、上面这段代码就是通过判断你是要增删改查的哪一种,我们这里调用的查方法,所以会到查询里面
2、到查询里面的判断后,会再次判断你的返回值是返回集合、还是返回的是map、还是单个的或者是其它的类型
我这里接下来会调用 MapperMethod#executeForMany()
java
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
// 解析你传的参数 ParamNameResolver
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
// 逻辑分页
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.selectList(command.getName(), param, rowBounds);
} else {
// command.getName()= 全类名+方法名 如:com.lizhi.dao.EmployeeDao.selectAll
result = sqlSession.selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}
通过 SqlSessionTemplate 类,调用 DefaultSqlSession#selectList() 来查询数据
java
public class DefaultSqlSession implements SqlSession {
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds,
ResultHandler handler) {
try {
// 这里的statement就是刚传过来的command.getName()也就是全类名
MappedStatement ms = configuration.getMappedStatement(statement);
// 通过执行器来查询(执行器也是四大对象之一)
return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
// 如果参数类型是集合的话,通过参数名字解析器包装成map
// 集合:key=list,value=值 数组:key=array,value=值
private Object wrapCollection(final Object object) {
return ParamNameResolver.wrapToMapIfCollection(object, null);
}
}
// 所有的配置都在这个里面,这里面有很多的东西
public class Configuration {
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
public MappedStatement getMappedStatement(String id) {
return this.getMappedStatement(id, true);
}
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
return mappedStatements.get(id);
}
}
# 四大对象之一
public class ParamNameResolver {
// 如果是集合/数组就包装一下,这也就是为啥我们传入的参数是集合类型时可以通过 list 当作名字来获取。数组也同理 array
public static Object wrapToMapIfCollection(Object object, String actualParamName) {
if (object instanceof Collection) {
ParamMap<Object> map = new ParamMap<>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
return map;
} else if (object != null && object.getClass().isArray()) {
ParamMap<Object> map = new ParamMap<>();
map.put("array", object);
Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
return map;
}
return object;
}
}
-
configuration.getMappedStatement() 从全局配置类中根据名字获取 MappedStatement 对象
1.1 wrapCollection() 包装参数 会调用 ParamNameResolver#wrapToMapIfCollection
-
executor.query() 通过执行器执行query方法 (四大核心对象之一露面了)
2.1 wrapCollection() 包装参数 会调用 ParamNameResolver#wrapToMapIfCollection
调用 CachingExecutor#query() 来查询
java
private final Executor delegate;
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 把参数传进去,构建一个 BoundSql 对象
BoundSql boundSql = ms.getBoundSql(parameterObject);
// 创建一个缓存key 这个key超级长
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
// 查询
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
继续调用重载的方法:org.apache.ibatis.executor.CachingExecutor#query() 来查询。这时候会查询二级缓存
java
private final Executor delegate;
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.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 继续调用查询,这次的executor是BaseExceutor
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
继续调用:BaseExecutor#query() 再查一下一级缓存
java
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++;
// 查询一级缓存
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);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
上面两个地方就告诉了我们,mybatis的缓存为啥是先查二级再查一级
org.apache.ibatis.executor.BaseExecutor#queryFromDatabase() 查询数据库
java
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;
}
org.apache.ibatis.executor.SimpleExecutor#doQuery():
java
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();
// 创建 StatementHandler 对象 默认是 PreparedStatementHandler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 获取一个 PreparedStatement 对象
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行SQL语句并通过ResultSetHandler处理返回结果
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
上面这个 doQuery() 方法的步骤分析:
第一步分析、configuration.newStatementHandler():
java
// org.apache.ibatis.session.Configuration类
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 根据具体的类型得到一个 StatementHandler
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 执行插件的 plugin() 方法
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
// RoutingStatementHandler类
private final StatementHandler delegate;
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;
// PreparedStatement 预编译的 默认
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());
}
}
// PreparedStatementHandler 类
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 调用父类(BaseStatementHandler)的构造方法创建
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
// BaseStatementHandler类
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 全局配置
this.configuration = mappedStatement.getConfiguration();
// 执行器
this.executor = executor;
// MappedStatement 还记得吗?一个增删改查标签就是一个MappedStatement对象
this.mappedStatement = mappedStatement;
// 逻辑分页
this.rowBounds = rowBounds;
// 类型处理器的注册 里面是java类型和数据库类型的映射关系
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
// 自动生成主键
generateKeys(parameterObject);
// SQL对象
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
// 四大对象之一:参数处理器
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 四大对象之一:结果集处理器
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
// InterceptorChain类 插件
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
总结:
1、创建StatementHandler时会根据对应的类型创建
2、创建StatementHandler时会填充一堆属性的值 包括(ParameterHandler、ResultSetHandler、TypeHandlerRegistry) TypeHandlerRegistry中注册了一堆TypeHandler。ParameterHandler、ResultSetHandler就是通过TypeHandler来做类型处理的
4、创建对应的对象时会执行对应的plugin()方法 如:StatementHandler、ParameterHandler、ResultSetHandler
第二步分析:SimpleExecutor#prepareStatement():ParameterHandler
java
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获取连接
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
// ParameterHandler 设置参数
handler.parameterize(stmt);
return stmt;
}
第三步分析:handler.query():ResultSetHandler
通过 RoutingStatementHandler#query() 调用到这里
java
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行
ps.execute();
// ResultSetHandler处理结果
return resultSetHandler.handleResultSets(ps);
}