一、准备工作


MyBatis 工作流程:应用程序首先加载 mybatis-config.xml 配置文件,并根据配置文件的内容创建 SqlSessionFactory 对象;然后,通过 SqlSessionFactory 对象创建 SqlSession 对象,SqlSession 接口中定义了执行 SQL 语句所需要的各种方法。之后,通过 SqlSession 对象执行映射配置文件中定义的 SQL 语句,完成相应的数据操作。最后通过 SqlSession 对象提交事务,关闭 SqlSession 对象,整个过程具体实现如下:就按照下面的流程进行源码分析

 1 public void test01() throws IOException {
2 // 1、获取sqlSessionFactory对象
3 String resource = "mybatis-config.xml";
4 InputStream inputStream = Resources.getResourceAsStream(resource);
5 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
6 // 2、获取sqlSession对象
7 SqlSession openSession = sqlSessionFactory.openSession();
8 try {
9 // 3、获取接口的实现类对象
10 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
11 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
12 Employee employee = mapper.getEmpById(1);
13 System.out.println(mapper);
14 System.out.println(employee);
15 } finally {
16 openSession.close();
17 }
18
19 }

二、SqlSessionFactory 对象的初始化过程


SqlSessionFactory  对象的初始化序列图如下:

【1】 从这行代码入手,首先创建了一个 SqlSessionFactoryBuilder 工厂,这是一个建造者模式的设计思想,由 builder 建造者来创建 SqlSessionFactory 工厂。

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

【2】 然后调用 SqlSessionFactoryBuilder 中的 build方法传递一个InputStream 输入流,Inputstream 输入流就是配置文件 mybatis-config.xml,SqlSessionFactoryBuilder 根据传入的 InputStream 输入流和environmentproperties属性创建一个 XMLConfigBuilder对象(解析器)。SqlSessionFactoryBuilder 对象调用 XMLConfigBuilder 的 parse()方法。配置文件中的内容被解析后封装到 Configuration 对象中。同时解析 mapper 标签。返回一个 XPathParser 类型的实例。

 1 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
2 //创建文件的解析器 XPathParse
3 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
4 return build(parser.parse());
5 }
6
7 //进入上述的内部方法 parser.parse()
8 public Configuration parse() {
9 parsed = true;
10 //获取 configuration 标签,全局最大的标签
11 parseConfiguration(parser.evalNode("/configuration"));
12 return configuration;
13 }
14
15 //进入上述的内部方法 parseConfiguration(parser.evalNode("/configuration"));
16 // 此方法中的方法内部都是将解析的标签内容 set 进 configuration 对象中
17 private void parseConfiguration(XNode root) {
18 Properties settings = settingsAsPropertiess(root.evalNode("settings"));
19 propertiesElement(root.evalNode("properties"));
20 //......
21
22 //将 setting 标签中的全局变量都set 到configuration 对象中
23 settingsElement(settings);
24
25 environmentsElement(root.evalNode("environments"));
26 databaseIdProviderElement(root.evalNode("databaseIdProvider"));
27 typeHandlerElement(root.evalNode("typeHandlers"));
28
29 //解析mapper 标签:很重要
30 mapperElement(root.evalNode("mappers"));
31 }
32
33 //列举上述 settingsElement(settings); 内部的源码
34 private void settingsElement(Properties props) throws Exception {
35 configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
36
37 //false 表示默认值
38 configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
39 configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
40 configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
41 //......
42 }

【3】解析 mapper.xml 文件,也是通过 XPathParser 类型的解析器,具体源码如下:将结果保存在 Configuration 中

 1 /**    配置信息如下:
2 <mappers>
3 <mapper resource="EmployeeMapper.xml" />
4 </mappers>
5 **/
6 private void mapperElement(XNode parent) throws Exception {
7 if (parent != null) {
8 for (XNode child : parent.getChildren()) {
9 String resource = child.getStringAttribute("resource");
10 String url = child.getStringAttribute("url");
11 String mapperClass = child.getStringAttribute("class");
12 if (resource != null && url == null && mapperClass == null) {
13 ErrorContext.instance().resource(resource);
14 //将配置文件转化为流文件,mapper.xml 文件
15 InputStream inputStream = Resources.getResourceAsStream(resource);
16 XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
17 //解析 mapper.xml 文件
18 mapperParser.parse();
19 }
20 }
21 }
22 }
23
24 //进入 mapperParser.parse(); 方法
25 public void parse() {
26 if (!configuration.isResourceLoaded(resource)) {
27 //解析 mapper标签中的内容
28 configurationElement(parser.evalNode("/mapper"));
29 configuration.addLoadedResource(resource);
30 bindMapperForNamespace();
31 }
32
33 parsePendingResultMaps();
34 parsePendingChacheRefs();
35 parsePendingStatements();
36 }
37
38 //进入 configurationElement(parser.evalNode("/mapper")); 方法
39 //解析mapper中的标签内容
40 private void configurationElement(XNode context) {
41 String namespace = context.getStringAttribute("namespace");
42 builderAssistant.setCurrentNamespace(namespace);
43 cacheRefElement(context.evalNode("cache-ref"));
44 cacheElement(context.evalNode("cache"));
45 parameterMapElement(context.evalNodes("/mapper/parameterMap"));
46 resultMapElements(context.evalNodes("/mapper/resultMap"));
47 sqlElement(context.evalNodes("/mapper/sql"));
48 //解析增删改查标签
49 buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
50 }

【4】解析 mapper 中的增删改查标签:拿到所有标签能写的属性,将详细信息保存进 MappedStatement(是一个Map,Key 存放的是 命令空间+id) 中,一个 MappedStatement 就代表一个增删改查标签的详细信息。

 1 // 进入增删改查标签的源码 buildStatementFromContext
2 private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
3 for (XNode context : list) {
4 //获取到 解析增删改查标签的解析器 statementParser
5 final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
6 //解析标签中的内容
7 statementParser.parseStatementNode();
8 }
9 }
10 public void parseStatementNode() {
11 String id = context.getStringAttribute("id");
12 String databaseId = context.getStringAttribute("databaseId");
13
14 if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
15 return;
16 }
17
18 Integer fetchSize = context.getIntAttribute("fetchSize");
19 Integer timeout = context.getIntAttribute("timeout");
20 String parameterMap = context.getStringAttribute("parameterMap");
21 String parameterType = context.getStringAttribute("parameterType");
22 //....
23
24 //将解析的结果进行封装
25 builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
26 fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
27 resultSetTypeEnum, flushCache, useCache, resultOrdered,
28 keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
29 }
30 }
31
32 //进入 builderAssistant.addMappedStatement 方法
33 public MappedStatement addMappedStatement(
34 //......
35 MappedStatement statement = statementBuilder.build();
36 //并将结果添加到 Configuration 中,MappedStatement 是一个 map 对象
37 configuration.addMappedStatement(statement);
38 return statement;
39 }

【5】Configuration 对象保存了所有配置文件的详细信息,包括全局配置文件和 sql 映射文件。
Configuration  中包含的 MappedStatement 对象信息:
Configuration  中包含的 MapperRegistory 对象,其中的 knownMappers 包含的是接口的代理对象。

【6】DefaultSqlSessionFactory传入上面返回的 Configuration 对象,通过 build 的方法创建一个 DefaultSqlSessionFactory 包含配置了全局信息的 Configuration;

public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}

DefaultSqlSessionFactory : SqlSessionFactory 的默认实现类,是真正生产会话的工厂类,这个类的实例的生命周期是全局的,它只会在首次调用时生成一个实例(单例模式),就一直存在直到服务器关闭。

三、SqlSession 对象的初始化过程


SqlSession 对象的初始化序列图如下:会创建 Executor

SqlSession 对象是 MyBatis 中最重要的一个对象,这个接口能够让你执行命令,获取映射,管理事务。SqlSession 中定义了一系列模版方法,让你能够执行简单的 CRUD 操作,也可以通过 getMapper 获取 Mapper 层,执行自定义 SQL 语句,因为 SqlSession 在执行 SQL 语句之前是需要先开启一个会话,涉及到事务操作,所以还会有 commitrollbackclose 等方法。这也是模版设计模式的一种应用。

【1】通过 DefaultSqlSessionFactory 的 openSession 方法获取 SqlSession;

SqlSession openSession = sqlSessionFactory.openSession();

【2】进入 openSession方法:需要传入 Executor 的类型,在配置文件中可以指定,默认是 simple;

1 public SqlSession openSession() {
2 //configuration.getDefaultExecutorType() 执行器Executor 的默认类型 simple(总共三种类型 reuse、simple、batch)
3 return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
4 }

【3】进入 openSessionFromDataSource 方法:重点是创建了 Executor执行器对象和 SqlSession 对象,传入事务和类型。

 1 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
2 Transaction tx = null;
3 try {
4 final Environment environment = configuration.getEnvironment();
5 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
6
7 //创建事务
8 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
9
10 //四大组件之一 Executor
11 final Executor executor = configuration.newExecutor(tx, execType);
12 return new DefaultSqlSession(configuration, executor, autoCommit);
13 }
14 }

【4】进入创建 Executor 的方法:configuration.newExecutor(tx, execType); Exeutor 是用来做增删改查的,里面包含了 query等方法;

 1 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
2 executorType = executorType == null ? defaultExecutorType : executorType;
3 executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
4 Executor executor;
5 //根据类型创建对应的 Executor
6 if (ExecutorType.BATCH == executorType) {
7 executor = new BatchExecutor(this, transaction);
8 } else if (ExecutorType.REUSE == executorType) {
9 executor = new ReuseExecutor(this, transaction);
10 } else {
11 //默认的 executor 是 SimpleExecutor
12 executor = new SimpleExecutor(this, transaction);
13 }
14 //是否开启的二级缓存,好处是查询之前会先从缓存中获取
15 if (cacheEnabled) {
16 executor = new CachingExecutor(executor);
17 }
18
19 //每一个 executor 都需要通过 拦截器进行重新包括(插件使用。。。。重要)
20 executor = (Executor) interceptorChain.pluginAll(executor);
21 return executor;
22 }

【5】展示 Executor 对象中的信息:

 1 public interface Executor {
2 //增删改查操作
3 int update(MappedStatement ms, Object parameter) throws SQLException;
4 <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
5 List<BatchResult> flushStatements() throws SQLException;
6
7 //事务相关操作
8 void commit(boolean required) throws SQLException;
9 void rollback(boolean required) throws SQLException;
10 //......
11 }

【6】创建 DefaultSqlSession 并将上述创建的 Executor传入,并包含 Configuration;

return new DefaultSqlSession(configuration, executor, autoCommit);

四、getMapper 对象的初始化过程


getMapper 对象的初始化序列图如下:  会创建 MapperProxy代理对象;MapperProxy 是 Mapper 映射 SQL 语句的关键对象,我们写的 Dao 层或者 Mapper 层都是通过 MapperProxy来和对应的 SQL语句进行绑定的。下面我们就来解释一下绑定过程。
 

【1】通过 getMapper 获取代理对象;

EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);

【2】进入 getMapper 方法内部,发现调用的是 Configuration 对象的 getMapper 方法,并将 SqlSession 作为参数传入;

public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}

【3】进入 Configuration 对象的 getMapper 方法,通过调用 mapperRegistry 对象的 getMapper 方法;

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}

【4】进入 MapperRegistry 的 getMapper 方法,根据接口类型获取其代理对象工厂 mapperProxyFactory;

1 @SuppressWarnings("unchecked")
2 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
3 //根据接口类型获取其代理对象
4 final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
5 // 会创建一个 mapperProxy
6 return mapperProxyFactory.newInstance(sqlSession);
7 }

【5】进入 mapperProxyFactory.newInstance(sqlSession); 方法,其主要是创建 MapperProxy 代理对象;

1 public T newInstance(SqlSession sqlSession) {
2 //获取代理对象
3 final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
4 return newInstance(mapperProxy);
5 }

【6】进入 MapperProxy 代理对象,主要包含如下三个属性:并且实现了 InvocationHandler,是JDK 动态代理的一部分;

1 public class MapperProxy<T> implements InvocationHandler, Serializable {
2
3 private static final long serialVersionUID = -6424540398559729838L;
4 //主要包含 sqlSession 、 mapper接口和 其中的方法
5 private final SqlSession sqlSession;
6 private final Class<T> mapperInterface;
7 private final Map<Method, MapperMethod> methodCache;
8 //......
9 }

【7】我们进入 5 中的 newInstance 方法:使用 JDK 实现动态代理 Proxy.newProxyInstance(....),创建 MapperProxy 代理对象。内部包含 SqlSession 进行增删改查。也就是说,MyBatis 中 Mapper 和 SQL 语句的绑定正是通过动态代理来完成的。通过动态代理,我们就可以方便的在 Dao 层或者 Mapper 层定义接口,实现自定义的增删改查操作了。

1 @SuppressWarnings("unchecked")
2 //JDK 动态代理
3 protected T newInstance(MapperProxy<T> mapperProxy) {
4 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
5 }

【8】代理对象展示:

五、通过代理对象调用目标方法的初始化过程


mapper.getEmpById(1) 查询执行的序列图如下:

【1】进入代理类调用目标方法入口:

Employee employee = mapper.getEmpById(1);

【2】首先会进入代理方法的 invoke 方法:

 1 //调用代理对象的入口
2 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
3 //首先判断调用的是不是 Object 对象的方法
4 if (Object.class.equals(method.getDeclaringClass())) {
5 try {
6 return method.invoke(this, args);
7 } catch (Throwable t) {
8 throw ExceptionUtil.unwrapThrowable(t);
9 }
10 }
11 //将当前方法包装成 MapperMethod
12 final MapperMethod mapperMethod = cachedMapperMethod(method);
13 return mapperMethod.execute(sqlSession, args);
14 }

【3】进入  mapperMethod.execute(sqlSession, args); 目标方法执行,传入 sqlSession 和参数;

 1 public Object execute(SqlSession sqlSession, Object[] args) {
2 Object result;
3 switch (command.getType()) {
4 case INSERT: {
5 Object param = method.convertArgsToSqlCommandParam(args);
6 result = rowCountResult(sqlSession.insert(command.getName(), param));
7 break;
8 }
9 case UPDATE: {
10 Object param = method.convertArgsToSqlCommandParam(args);
11 result = rowCountResult(sqlSession.update(command.getName(), param));
12 break;
13 }
14 case DELETE: {
15 Object param = method.convertArgsToSqlCommandParam(args);
16 result = rowCountResult(sqlSession.delete(command.getName(), param));
17 break;
18 }
19 case SELECT:
20 //当前方法无返回值时执行
21 if (method.returnsVoid() && method.hasResultHandler()) {
22 executeWithResultHandler(sqlSession, args);
23 result = null;
24 //返回多个执行方法
25 } else if (method.returnsMany()) {
26 result = executeForMany(sqlSession, args);
27 //返回Map执行
28 } else if (method.returnsMap()) {
29 result = executeForMap(sqlSession, args);
30 //返回游标执行
31 } else if (method.returnsCursor()) {
32 result = executeForCursor(sqlSession, args);
33 } else {
34 //其余执行此方法
35 //该方法是将当前参数:如果是1个参数则返回,如果多个则组装成 map 返回
36 Object param = method.convertArgsToSqlCommandParam(args);
37 result = sqlSession.selectOne(command.getName(), param);
38 }
39 break;
40 return result;
41 }

【4】调用单个查询 sqlSession.selectOne 方法:调用查询多个的方法,返回 list的第一个元素即可;statement 就是当前sql 的唯一表示,对应 xml 中的 namespace;

 1 public <T> T selectOne(String statement, Object parameter) {
2 List<T> list = this.<T>selectList(statement, parameter);
3 if (list.size() == 1) {
4 return list.get(0);
5 } else if (list.size() > 1) {
6 throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
7 } else {
8 return null;
9 }
10 }

【5】进入 selectList(statement, parameter); 方法:会获取 mapperedStatement 对象,同时调用 Executor 的query 方法执行

1 @Override
2 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
3 try {
4 //首先获取 mapperedStatement 对象
5 MappedStatement ms = configuration.getMappedStatement(statement);
6 //通过 executor 的query 方法执行
7 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
8 }
9 }

【6】获取 mapperedStatement 通过 BoundSql 它代表 sql 语句的详细信息:通过query 方法进行查询;

1 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
2 BoundSql boundSql = ms.getBoundSql(parameter);
3 CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
4 return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
5 }

【7】进入上述的 query 方法,先调用 cacheExecutor 缓存,如果不存在则调用全局配置 Executor ,我们这里使用的默认 simpleExecutor 方法:先会调用二级缓存,再调用一级缓存;如果不存在则执行 queryFromDatabase 查出以后也会保存在以及缓存中;

 1 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
2 //先调用本地缓存
3 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
4 if (list != null) {
5 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
6 } else {
7 //如果缓存中不存在,则调用 queryFromDatabase
8 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
9 }
10 return list;
11 }

【8】进入 queryFromDatabase 方法:调用 BaseExecutor 对象中的 doQuery方法   ms 当前增删改查标签的详细信息

1 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
2 try {
3 //调用 BaseExecutor对象中的 doQuery方法 ms 当前增删改查标签的详细信息
4 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
5 }
6 return list;
7 }

【9】进入 SimpleExecutor 对象的 doQuery 方法:底层包含了 Statement 对象,表示对 JDBC 的封装,同时创建了四大对象之一 StatementHandler 作用:创建 Statement 对象;在创建 StatementHandler 的时候构造器里面会同时创建 ParameterHandler和 ResultSetHandler。

 1 public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
2 //原生 JDBC 的 Statement对象
3 Statement stmt = null;
4 try {
5 Configuration configuration = ms.getConfiguration();
6 //创建四个对象之一 StatementHandler
7 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
8 //从 StatementHandler 中获取 Statement 对象
9 stmt = prepareStatement(handler, ms.getStatementLog());
10 return handler.<E>query(stmt, resultHandler);
11 }
12 }

【10】进入 newStatementHandler 方法,查看 StatementHandler 对象的创建;

1 public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
2 StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
3 //使用拦截器链包装 StatementHandler
4 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
5 return statementHandler;
6 }

【11】进入 RoutingStatementHandler 方法:我们可以在查询标签中设置 StatementType 就根据如下方法创建我们需要的 Statement 对象;默认使用的是 PREPARED(预编译的形式),会创建一个 PreparedStatementHandler;

 1 public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
2
3 switch (ms.getStatementType()) {
4 case STATEMENT:
5 delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
6 break;
7 case PREPARED:
8 delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
9 break;
10 case CALLABLE:
11 delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
12 break;
13 default:
14 throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
15 }
16 }

【12】通过 StatementHandler 创建 Statement 对象,进入 stmt = prepareStatement(handler, ms.getStatementLog()); 方法:预编译 sql 产生的 PreparedStatement 对象,调用四大对象之一 ParameterHandler 进行参数的预编译;也是 JDBC 原生的对象;

 1 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
2 Statement stmt;
3 //创建一个链接
4 Connection connection = getConnection(statementLog);
5 //进行预编译
6 stmt = handler.prepare(connection, transaction.getTimeout());
7 //进行参数预编译
8 handler.parameterize(stmt);
9 return stmt;
10 }

【13】进入创建 ParameterHandler 的方法:newParameterHandler(mappedStatement, parameterObject, boundSql); 同时也调用了 pluginAll 方法,通过拦截器链对 ParameterHandler  进行封装;

1 public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
2 ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
3 //也调用了拦截器链
4 parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
5 return parameterHandler;
6 }

【14】进入创建 ResultSetHandler 的方法:configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql); 同时也调用了 pluginAll 方法,通过拦截器链对 ParameterHandler  进行封装;也输入四大对象之一;用于处理查询得到的数据;

1 public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
2 ResultHandler resultHandler, BoundSql boundSql) {
3 ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
4 //也调用了拦截器链
5 resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
6 return resultSetHandler;
7 }

【15】最终返回执行的结果和关闭连接,以及查询流程总结:
    ■ StatementHandler处理 sql语句预编译,设置参数等相关工作;
    ■ ParameterHandler设置预编译参数用的;
    ■ResultHandler处理结果集;
    ■TypeHandler在整个过程中,进行数据库类型和 javaBean类型的映射;

六、总结


【1】根据配置文件(全局,sql映射)初始化出 Configuration 对象;
【2】创建一个 DefaultSqlSession对象,他里面包含 Configuration以及 Executor(根据全局配置文件中的 defaultExecutorType创建出对应的 Executor);
【3】DefaultSqlSession.getMapper():拿到 Mapper接口对应的 MapperProxy;
【4】MapperProxy里面有(DefaultSqlSession);
【5】执行增删改查方法:
    1)、代理对象调用 DefaultSqlSession 的增删改查(最终调用 Executor 的增删改查);
    2)、会创建一个 StatementHandler 对象。(同时也会创建出 ParameterHandler 和 ResultSetHandler)
    3)、调用 StatementHandler预编译参数以及设置参数值,使用 ParameterHandler 来给 sql设置参数;
    4)、调用 StatementHandler 的增删改查方法;
    5)、ResultSetHandler 封装结果;
注意:四大对象每个创建的时候都有一个 interceptorChain.pluginAll(parameterHandler);后面的插件应用中使用;

----关注公众号,获取更多内容----

 

MyBatis 源码的更多相关文章

  1. MyBatis源码分析(一)开篇

    源码学习的好处不用多说,Mybatis源码量少.逻辑简单,将写个系列文章来学习. SqlSession Mybatis的使用入口位于org.apache.ibatis.session包中的SqlSes ...

  2. MyBatis源码分析-MyBatis初始化流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  3. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  4. MyBatis源码分析-IDEA新建MyBatis源码工程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  5. MyBatis源码分析(5)——内置DataSource实现

    @(MyBatis)[DataSource] MyBatis源码分析(5)--内置DataSource实现 MyBatis内置了两个DataSource的实现:UnpooledDataSource,该 ...

  6. MyBatis源码分析(4)—— Cache构建以及应用

    @(MyBatis)[Cache] MyBatis源码分析--Cache构建以及应用 SqlSession使用缓存流程 如果开启了二级缓存,而Executor会使用CachingExecutor来装饰 ...

  7. MyBatis源码分析(3)—— Cache接口以及实现

    @(MyBatis)[Cache] MyBatis源码分析--Cache接口以及实现 Cache接口 MyBatis中的Cache以SPI实现,给需要集成其它Cache或者自定义Cache提供了接口. ...

  8. MyBatis源码分析(2)—— Plugin原理

    @(MyBatis)[Plugin] MyBatis源码分析--Plugin原理 Plugin原理 Plugin的实现采用了Java的动态代理,应用了责任链设计模式 InterceptorChain ...

  9. 深入浅出Mybatis系列(五)---TypeHandler简介及配置(mybatis源码篇)

    上篇文章<深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)>为大家介绍了mybatis中别名的使用,以及其源码.本篇将为大家介绍TypeH ...

  10. 深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)

    上篇文章<深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)> 介绍了properties与environments, ...

随机推荐

  1. shell_Day01

    1.判断/etc/inittab文件是否大于100行,如果大于,则显示"/etc/inittab is a big file."否者显示"/etc/inittab is ...

  2. flask、element、vue项目实战:搭建一个加密excel数据的网站

    文章目录 一.前端 1.1 上传文件 1.2 数据表格 1.3 加密选项 1.4 加密数据 1.5 下载按钮 二.后端 2.1 .upload 文件上传 2.2 table 数据表格接口 2.3 en ...

  3. Linux 第二节(基本命令)

    www.linuxcool.com 一.ifconfig 1.Ip 地址 2.MAC地址 3.收到的数据包(RX) 4.发送的数据包(Tx) 二.uname uname -a    //查看系统内核及 ...

  4. uiautomator2自动化工具的下载与安装

    前言: 相信很多使用appium做过APP自动化的人都深有感触: 1,安装麻烦,配置环境可能会难道不少人 2,appium运行慢.时间长 3,uiautomatorviewer定位元素时得关掉appi ...

  5. Python openpyxl【包】

    介绍 Excel是我们日常工作中经常用到的办公软件,在处理数据和表格方面有着优异的性能,那么能不能用python来操作Excel呢? 答案是肯定的,openpyxl是一个第三方库,可以处理xlsx格式 ...

  6. Java 基础(二)

    类的初始 类中包括:属性,方法. 快速使用 我们都是人,而人的共同特点有很多. 比如:名字,年龄,性别,吃饭,睡觉... // 定义类 public class Person { // 定义属性 St ...

  7. nuttx理解

    操作系统:为啥要引入操作系统,个人的理解是为了实时性(即及时的响应性). 没有操作系统下多个任务都只能以前后台的方式排队执行,对某个任务的输入不能得到及时的响应:虽然后台有中断,但不能把所有的任务都放 ...

  8. pycharm debug 等实用功能

    1.debug方法方法一: 1.打断点,代码会运行到断点前一行 2.step over 逐行运行代码 3.鼠标选中带有函数语句的当前行,点击 step into 再点击step over代码会跳转到函 ...

  9. JavaScript的Object.defineProperty( )方法

    Object.defineProperty方法可以在一个对象上定义一个新的属性,或者修改该对象原有的属性,并返回该对象. 基础的语法格式如下: 1 var data = {}//定义一个对象 2 Ob ...

  10. @DeclareParents声明对象的AOP

    今天在使用@DeclareParents时,使用AspectJ拓展对象的接口 public interface Encoreable { void nextPerformance(); } @Comp ...