接着上一篇
分析源码,从编程式的 demo 入手
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlogById(1);
我们开始第二步源码分析
SqlSession session = sqlSessionFactory.openSession();
会话创建过程
我们知道,第一步获取的sqlSessionFactory是DefaultSqlSessionFactory,所以直接去它的openSession方法查看源码
public class DefaultSqlSessionFactory implements SqlSessionFactory {
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
//1.先从 Configuration 里面拿到 Enviroment,Enviroment 里面就有事务工厂
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
//2.创建 Transaction
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//3.创建 Executor
Executor executor = this.configuration.newExecutor(tx, execType);
//4.最终返回 DefaultSqlSession,属性包括 Configuration、Executor 对象
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
}
1.先从 Configuration 里面拿到 Enviroment,Enviroment 里面就有事务工厂
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
我们知道这个标签就是配置数据源和事务的,如下
2.创建 Transaction
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
- 如果配置的是 JDBC,则会使用 Connection 对象的 commit()、rollback()、close() 管理事务
- 如果配置成 MANAGED,会把事务交给容器来管理,比如 JBOSS,Weblogic
-
如 果 是 Spring + MyBatis , 则 没 有 必 要 配 置 , 因 为 我 们 会 直 接 在applicationContext.xml 里面配置数据源和事务管理器,覆盖 MyBatis 的配置
可以看看这个方法的三个实现类
3.创建 Executor
Executor executor = this.configuration.newExecutor(tx, execType);
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
//第一次判断有木有配置executorType ,没有配置用defaultExecutorType的配置
executorType = executorType == null ? this.defaultExecutorType : executorType;
//第二次又判断,是为了,假如有傻子故意把defaultExecutorType配置为null,默认设置SIMPLE
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Object executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
//是否开启了二级缓存,由一个缓存包装类CachingExecutor来执行
if (this.cacheEnabled) {
executor = new CachingExecutor((Executor)executor);
}
//executor 添加到插件中
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
return executor;
}
Executor 的基本类型有三种:SIMPLE、BATCH、REUSE,默认是 SIMPLE
(settingsElement()读取默认值),他们都继承了抽象类 BaseExecutor。
三种类型的区别:
- SimpleExecutor
每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。 - ReuseExecutor
执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map 内,供下一次使用。简言之,就是重复使用 Statement 对象 - BatchExecutor
执行 update(没有 select,JDBC 批处理不支持 select),将所
有 sql 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存
了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行
executeBatch()批处理。与 JDBC 批处理相同
总结:创建会话的过程,我们获得了一个 DefaultSqlSession,里面包含了一个Executor,它是 SQL 的执行者
获得 Mapper 对象
现在我们已经有一个 DefaultSqlSession 了,必须找到 Mapper.xml 里面定义的Statement ID,才能执行对应的 SQL 语句。
找到 Statement ID 有两种方式:
- 第一种是直接调用 session 的方法,在参数里面传入Statement ID,这种方式属于硬编码,我们没办法知道有多少处调用,修改起来也很麻烦。另一个问题是如果参数传入错误,在编译阶段也是不会报错的,不利于预先发现问题
Blog blog = (Blog) session.selectOne("com.wei.mapper.BlogMapper.selectBlogById", 1);
- 第二种就是我们的编程式方法,定义一个接口,然后再调用Mapper 接口的方法。由于我们的接口名称跟 Mapper.xml 的 namespace 是对应的,接口的方法跟 statement ID 也都是对应的,所以根据方法就能找到对应的要执行的 SQL。
BlogMapper mapper = session.getMapper(BlogMapper.class);
我们需要了解这个mapper对象是怎么获取的,它到底是一个什么对象(目前从代码来看仅仅是一个接口而已)?
直接跟进DefaultSqlSession 的getMapper方法
public class DefaultSqlSession implements SqlSession {
public T getMapper(Class type) {
return this.configuration.getMapper(type, this);
}
...
}
进入跟进Configuration的getMapper方法
public T getMapper(Class type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
我们知道,在解析 mapper 标签和 Mapper.xml 的时候已经把接口类型和类型对应的 MapperProxyFactory 放到了一个 Map 中。获取 Mapper 代理对象,实际上是从Map 中获取对应的工厂类后,调用MapperRegistry的getMapper方法创建对象
public class MapperRegistry {
private final Configuration config;
//接口类型和类型对应的 MapperProxyFactory
private final Map, MapperProxyFactory>> knownMappers = new HashMap();
public MapperRegistry(Configuration config) {
this.config = config;
}
public T getMapper(Class type, SqlSession sqlSession) {
MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
//跟进代码可知通过jdk动态代理获取一个代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
}
mapperProxyFactory.newInstance(sqlSession);
跟进代码可知通过jdk动态代理获取一个代理对象
public class MapperProxyFactory {
private final Class mapperInterface;
private final Map methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class getMapperInterface() {
return this.mapperInterface;
}
public Map getMethodCache() {
return this.methodCache;
}
protected T newInstance(MapperProxy mapperProxy) {
//因为mapper都是接口,通过jdk动态代理实现即可
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
//这个MapperProxy,就是真正的mapper对象,一个代理对象
MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
}
从上面代码可知,mapper最终的对象就是一个MapperProxy 对象(代理对象),而且是jdk动态代理实现,那么肯定实现了invoke方法,代表每次调用mapper的任意方法,都会进入他的invoke方法,我们可以看看这个代理对象MapperProxy 的代码
public class MapperProxy implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class mapperInterface;
private final Map methodCache;
public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
});
}
private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
Constructor constructor = Lookup.class.getDeclaredConstructor(Class.class, Integer.TYPE);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
Class> declaringClass = method.getDeclaringClass();
return ((Lookup)constructor.newInstance(declaringClass, 15)).unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
}
private boolean isDefaultMethod(Method method) {
return (method.getModifiers() & 1033) == 1 && method.getDeclaringClass().isInterface();
}
}
注:JDK 动态代理代理,在实现了 InvocationHandler 的代理类里面,需要传入一个被代理对象的实现类,MyBatis 的动态代理缺不需要实现类,因为它只需要根据接口类型+方法的名称,就可以找到Statement ID 了,而唯一要做的一件事情也是这件,所以不需要实现类,在 MapperProxy里面直接执行逻辑(也就是执行 SQL)就可以了。
总结:获得 Mapper 对象的过程,实质上是获取了一个 MapperProxy 的代理对象。
MapperProxy 中有 sqlSession、mapperInterface、methodCache
执行 SQL
我们来到最后一步Blog blog = mapper.selectBlogById(1);真正执行sql
由于所有的 Mapper 都是 MapperProxy 代理对象,所以任意的方法都是执行MapperProxy 的 invoke()方法,那我们直接看MapperProxy 的invoke方法即可
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//Object 本身的方法不需要去执行 SQL
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
//Java 8 中接口的默认方法(jdk8支持接口有默认实现)不需要去执行 SQL
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
// 获取缓存,保存了方法签名和接口方法的关系
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
可以断点进去看看传入的值
从这里debug进去 Blog blog = mapper.selectBlogById(1);
this.cachedMapperMethod(method); 跟进这个代码看看
private MapperMethod cachedMapperMethod(Method method) {
return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
});
}
public class MapperMethod {
private final MapperMethod.SqlCommand command;
private final MapperMethod.MethodSignature method;
public MapperMethod(Class> mapperInterface, Method method, Configuration config) {
//调用一个内部类,获取要执行的具体mapper中对应的Statement
this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
//调用一个内部类,获取要执行的具体mapper接口方法
this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
}
public static class SqlCommand {
private final String name;
private final SqlCommandType type;
public SqlCommand(Configuration configuration, Class> mapperInterface, Method method) {
String methodName = method.getName();
Class> declaringClass = method.getDeclaringClass();
//跟进接口类型,方法名,对应configuration中的xml配置匹配到mapper中对应的Statement
MappedStatement ms = this.resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration);
...
//找到mapper.xml中的id,如:com.wei.mapper.BlogMapper.selectBlogById
this.name = ms.getId();
//找到mapper.xml中的type,如:SELECT
this.type = ms.getSqlCommandType();
if (this.type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + this.name);
}
...
}
}
public static class MethodSignature {
private final boolean returnsMany;
private final boolean returnsMap;
private final boolean returnsVoid;
private final boolean returnsCursor;
private final boolean returnsOptional;
private final Class> returnType;
private final String mapKey;
private final Integer resultHandlerIndex;
private final Integer rowBoundsIndex;
private final ParamNameResolver paramNameResolver;
public MethodSignature(Configuration configuration, Class> mapperInterface, Method method) {
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class) {
this.returnType = (Class)resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class)((ParameterizedType)resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
this.returnsVoid = Void.TYPE.equals(this.returnType);
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
this.returnsCursor = Cursor.class.equals(this.returnType);
this.returnsOptional = Optional.class.equals(this.returnType);
this.mapKey = this.getMapKey(method);
this.returnsMap = this.mapKey != null;
this.rowBoundsIndex = this.getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = this.getUniqueParamIndex(method, ResultHandler.class);
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
}
}
以上代码可以看看内部注释,主要就是获取一个MapperMethod对象,里面有两个属性,一个是 SqlCommand , 一 个 是MethodSignature,这两个都是 MapperMethod 的内部类,断点值如下图所示:
我们接着跟进mapperMethod.execute(this.sqlSession, args); 方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
switch(this.command.getType()) {
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
在这一步,根据不同的 type 和返回类型:
调用 convertArgsToSqlCommandParam()将参数转换为 SQL 的参数。
调用 sqlSession 的 insert()、update()、delete()、selectOne ()方法,我们以查询为例,会走到 selectOne()方法
public class DefaultSqlSession implements SqlSession {
public T selectOne(String statement, Object parameter) {
//最终还是调用到selectList
List list = this.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;
}
}
public List selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
public List selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
MappedStatement ms = this.configuration.getMappedStatement(statement);
var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception var9) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9);
} finally {
ErrorContext.instance().reset();
}
return var5;
}
...
}
在 selectList()中,我们先根据 command name(Statement ID)从 Configuration
中拿到 MappedStatement,这个 ms 上面有我们在 xml 中配置的所有属性,包括 id、
statementType、sqlSource、useCache、入参、出参等等
我们断点看看:
从map里面找到对应的ms
最终调用this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
即执行了 Executor 的 query()方法
我们知道Executor 有三种基本类型SIMPLE/REUSE/BATCH,还有一种包装类型,CachingExecutor。
那么在这里到底会选择哪一种执行器呢?
回过头去看看 DefaultSqlSession 在初始化的时候是怎么赋值的,这个就是我们的会话创建过程,
- 如果启用了二级缓存,就会先调用 CachingExecutor 的 query()方法,里面有缓存相关的操作,然后才是再调用基本类型的执行器,比如默认的 SimpleExecutor
- 如果没有开启二级缓存,先会走到 BaseExecutor 的 query()方法(否则会先走到 CachingExecutor)
接下来以两种方式来分析源码:
第一种是没开启二级缓存,走BaseExecutor 的 query()方法,我们跟进代码看看
public abstract class BaseExecutor implements Executor {
private static final Log log = LogFactory.getLog(BaseExecutor.class);
protected Transaction transaction;
protected Executor wrapper;
protected ConcurrentLinkedQueue deferredLoads;
protected PerpetualCache localCache;//一级缓存对象
protected PerpetualCache localOutputParameterCache;
protected Configuration configuration;
protected int queryStack;
private boolean closed;
public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//获取sql语句,和参数值
BoundSql boundSql = ms.getBoundSql(parameter);
//获取缓存key(id+sql语句+参数值等等组成)
//如:-525700837:2796097031:com.wei.mapper.BlogMapper.selectBlogById:0:2147483647:select //* from blog where bid = ?:1:development
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
public List 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 (this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
this.clearLocalCache();
}
List list;
try {
++this.queryStack;
//先从一级缓存获取
list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
if (list != null) {
this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//一级缓存中没有数据,直接查询数据库,跟进此代码
list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
--this.queryStack;
}
if (this.queryStack == 0) {
Iterator var8 = this.deferredLoads.iterator();
while(var8.hasNext()) {
BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
deferredLoad.load();
}
this.deferredLoads.clear();
if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
this.clearLocalCache();
}
}
return list;
}
}
}
跟进 this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); 方法
private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
//把这个key set到一级缓存中,value相当于一个占位符而已
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
//最终的执行query方法,根据配置来走不同的SIMPLE/REUSE/BATCH执行器
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
//一级缓存删除这个key
this.localCache.removeObject(key);
}
//重新真正set 到一级缓存中
this.localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
this.localOutputParameterCache.putObject(key, parameter);
}
return list;
}
//最终的执行query方法,根据配置来走不同的SIMPLE/REUSE/BATCH执行器
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
继续跟进这个方法,我们配置的是默认的SimpleExecutor
public class SimpleExecutor extends BaseExecutor {
public List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
Configuration configuration = ms.getConfiguration();
//创建StatementHandler对象,根据配置有三种可选(SimpleStatementHandler/PreparedStatementHandler/CallableStatementHandler)
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//预处理,set参数之类的
stmt = this.prepareStatement(handler, ms.getStatementLog());
//最终执行
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
}
//创建StatementHandler对象,根据配置有三种可选(SimpleStatementHandler/PreparedStatementHandler/CallableStatementHandler)
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
跟进代码,我们用的是PreparedStatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
//StatementHandler 加入到插件中,目前我们知道还有Executor也加入到插件中
StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
跟进这个new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 代码
public class PreparedStatementHandler extends BaseStatementHandler {
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 跟进super
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
}
接着跟进super
public abstract class BaseStatementHandler implements StatementHandler {
protected final Configuration configuration;
protected final ObjectFactory objectFactory;
protected final TypeHandlerRegistry typeHandlerRegistry;
protected final ResultSetHandler resultSetHandler;
protected final ParameterHandler parameterHandler;
protected final Executor executor;
protected final MappedStatement mappedStatement;
protected final RowBounds rowBounds;
protected BoundSql boundSql;
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 = this.configuration.getTypeHandlerRegistry();
this.objectFactory = this.configuration.getObjectFactory();
if (boundSql == null) {
this.generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
//这里创建了parameterHandler
this.parameterHandler = this.configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
//这里创建了resultSetHandler
this.resultSetHandler = this.configuration.newResultSetHandler(executor, mappedStatement, rowBounds, this.parameterHandler, resultHandler, boundSql);
}
这里创建了两个很重要的对象parameterHandler 和resultSetHandler,都是包含在StatementHandler 对象中的属性 ,并且跟进这个创建对象的方法,都会发现,这两个对象也加入了interceptorChain
parameterHandler = (ParameterHandler)this.interceptorChain.pluginAll(parameterHandler);
ResultSetHandler resultSetHandler = (ResultSetHandler)this.interceptorChain.pluginAll(resultSetHandler);
稍微提一下,这个插件对象
public class InterceptorChain {
//就是一个list的拦截器,可以全局配置,在几个组件中做拦截功能,
//目前有4个组件都加入到这个list中(Executor/StatementHandler/
ParameterHandler/ResultSetHandler )
private final List interceptors = new ArrayList();
public InterceptorChain() {
}
public Object pluginAll(Object target) {
Interceptor interceptor;
for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {
interceptor = (Interceptor)var2.next();
}
return target;
}
关于这个插件,我们在下一篇《5.MyBatis 插件原理与自定义插件》中会详细介绍
//回到之前的代码最终会执行
var9 = handler.query(stmt, resultHandler); 跟进这个方法,就会找到原生的jdbc操作数据库的代码,这里就不继续分析,大家可以debug
至于第二种配置了二级缓存的方式,
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
Cache cache = ms.getCache();
//先判断是mapper.xml 否配置缓存标签,如果没配置不能走缓存,
//这个逻辑告诉我们,即使在全局配置文件配置开启了二级缓存
//但是单个mapper映射文件没有配置,也是不生效的
if (cache != null) {
this.flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
this.ensureNoOutParams(ms, boundSql);
List list = (List)this.tcm.getObject(cache, key);
if (list == null) {
//缓存没有数据,直接走BaseExecutor的query方法
list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
//查询成功,放入二级缓存中
this.tcm.putObject(cache, key, list);
}
return list;
}
}
//没有配置,直接走BaseExecutor的query方法
return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
通过断点可知,这个二级缓存就是一个TransactionalCache 对象
public class TransactionalCacheManager {
private final Map transactionalCaches = new HashMap();
...
}
通过两篇文章,总结一下mybatis用到的所有对象
——学自咕泡学院