1、传统方式

1、编写测试类

image.png

2、如何将配置文件读取成字节输入流

  1. // 1. 读取配置文件,读成字节输入流,注意:现在还没解析
  2. InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

1、点击进入getResourceAsStream方法

image.png

2、点击进入getResourceAsStream的重载方法

image.png

3、根据配置文件的路径加载为字节输入流

image.png

3、如何解析配置文件的呢?

  1. // 2. 解析配置文件,封装Configuration对象 创建DefaultSqlSessionFactory对象
  2. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

1、点击进入build方法

build方法1、是解析配置文件。2、是创建SqlSessionFactory实现类对象
image.png

2、点击进入重载方法

image.png

3、点击进入parse方法

image.png

4、点击进入parseConfiguration方法

解析 XML 成 Configuration 对象
image.png

5、点击进入properties解析方法

image.png

6、对properties标签进行解析并将结果存到Configration对象中

image.png

7、同时解析 标签

image.png
image.png
image.png

还有很多细节的部分。

8、点击进入build方法(参数是封装后的Configration)

image.png

9、创建DefaultSqlSessionFactory对象

最后将封装好的对象,进行返回。然后就能从里面取出对应的方法进行使用了。
image.png

源码剖析-执行SQL流程

先简单介绍

SqlSession:

SqlSession是一个接口, 它有两个实现类:DefaultSqlSession(默认) 和 SqlSessionManager(弃用,不做介绍)
SqlSession是MyBatis中用于和数据库交互的顶层类, 通常将它与ThreadLocal绑定, 一个会话使用一个SqlSession(是线程不安全的), 并且在使用完毕后需要close。

public class DefaultSqlsession implements SqlSession{
private final Configuration configuration;
private final Executor executor;

sqlsession中的两个最重要的参数, configuration与初始化时的相同, Executor为执行器

Executor:

Executor也是一个接口, 他有三个常用的实现类:

  1. Batch Executor(重用语句并执行批量更新)
  2. Reuse Executor
  3. simple Executor(普通的执行器, 默认)

继续分析, 初始化完毕后, 我们就要执行SQL了
(重用预处理语句preparedstatements)

4、openSession如何生成SqlSession

  1. // 3. 生产了DefaultSqlsession实例对象 设置了事务不自动提交 完成了executor对象的创建
  2. SqlSession sqlSession = sqlSessionFactory.openSession();

1、点进入openSession

image.png

2、进入DefaultSqlSessionFactory实现类

image.png
进入到实现类工厂
image.png

3、点击进入默认执行器的类型

(调用的是无参的openSession方法嘛!)
image.png

4、点击进入defaultExecutorType

image.png

5、ExecutorType.SIMPLE类型

image.png

6、点击进入openSessionFromDataSource方法

image.png

7、创建实现类对象

image.png

image.png

5、sqlSession调用方法的具体流程

上面已经返回的是new DefaultSqlSession对象,返回Sqlsession,接下来可以调用Sqlsession里面的方法了。
第五小步截图有清晰的分析。

  1. // 4.(1)根据statementid,从Configuration中map集合中获取到了指定的MappedStatement对象
  2. //(2)将查询任务委派了executor执行器
  3. List<Object> objects = sqlSession.selectList("namespace.id");

1、点击进入selectList

image.png

2、点击进入DefaultSqlSession实现类

image.png

3、继续点击进入重载方法

image.png

4、继续点击进入重载方法

image.png

5、最终调用执行器的query方法

image.png

6、执行器executor源码剖析

1、点击进入query方法

image.png

2、点击进入query的实现类

image.png

3、在BaseExecutor父类中查看具体实现

image.png

4、点击进入query的方法

image.png

5、进入queryFromDatabase方法去数据库中取

image.png

6、点击进入doQuery查看数据库真正的读操作

image.png

7、点击进入实现类

image.png

8、点击进入调用预编译

image.png

9、初始化 StatementHandler 对象

image.png

10、委托StatementHandler的query方法去执行

image.png

7、StatementHandler的源码剖析

(自定义封装的是通过反射封装到对象,这里是通过StatementHandler处理,具体如下:)

1、点击进入parameterize方法

image.png

2、点击进入默认实现类

image.png

3、点击进入setParameters方法查看如何赋值

image.png

4、点击进入实现类

image.png

5、实现了StatementHandler委托typeHandler操作

image.png

  1. @SuppressWarnings("Duplicates")
  2. @Override
  3. public void setParameters(PreparedStatement ps) {
  4. ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  5. // 遍历 ParameterMapping 数组
  6. List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  7. if (parameterMappings != null) {
  8. for (int i = 0; i < parameterMappings.size(); i++) {
  9. // 获得 ParameterMapping 对象
  10. ParameterMapping parameterMapping = parameterMappings.get(i);
  11. if (parameterMapping.getMode() != ParameterMode.OUT) {
  12. // 获得值
  13. Object value;
  14. String propertyName = parameterMapping.getProperty();
  15. if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
  16. value = boundSql.getAdditionalParameter(propertyName);
  17. } else if (parameterObject == null) {
  18. value = null;
  19. } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
  20. value = parameterObject;
  21. } else {
  22. MetaObject metaObject = configuration.newMetaObject(parameterObject);
  23. value = metaObject.getValue(propertyName);
  24. }
  25. // 获得 typeHandler、jdbcType 属性
  26. TypeHandler typeHandler = parameterMapping.getTypeHandler();
  27. JdbcType jdbcType = parameterMapping.getJdbcType();
  28. if (value == null && jdbcType == null) {
  29. jdbcType = configuration.getJdbcTypeForNull();
  30. }
  31. // 设置 ? 占位符的参数
  32. try {
  33. typeHandler.setParameter(ps, i + 1, value, jdbcType);
  34. } catch (TypeException | SQLException e) {
  35. throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  36. }
  37. }
  38. }
  39. }
  40. }

6、点击进入SimpleExecutor类的query

handler.query(stmt, resultHandler);进行了查询,并将结果集封装。具体如下:
image.png

7、点击进入query方法的实现类

image.png

8、点击进入handleResultSets方法

image.png

9、点击进入其实现类

image.png

10、点击进入getFirstResultSet

image.png

11、将 ResultSet 对象,封装成 ResultSetWrapper 对象进行返回

image.png

12、再点击进入handleResultSets方法的handleResultSet方法

将_ResultSet 结果添加到 multipleResults 中_
image.png

13、处理 ResultSet ,将结果添加到 multipleResults 中

具体的添加如下:
image.png

2、Mapper代理的方式

1、使用方式如下

1、先添加一个接口类及接口方法

image.png

2、使用JDK动态代理对mapper接口产生代理对象

image.png

3、添加扫描的配置文件

image.png

4、用3的方式扫描接口、当完成2的操作后,还要去做build操作.

具体要看源码进行查看

2、build方法的源码剖析

1、先点击如build方法

image.png

2、再继续进入

image.png

3、点击进入parse方法

image.png

4、点击进入parseConfiguration方法

image.png

5、点击进入mapperElement方法

image.png

6、点击进入addMappers方法

image.png

7、再点击进入mapperRegistry

image.png

8、点击进入MapperRegistry对象

image.png

9、每一个接口对应着一个工厂image.png

3、getMapper方法的源码剖析

mapperProxyFactory的先创建,然后实例化MapperProxy对象。再进行实例化newInstance
MapperProxy实现了InvocationHandler接口,必然上面调用时候会执行invoke
invoke方法里面调用mapperMethod.execute()方法,去判断&执行底层sql

1、点击进入getMapper方法

image.png

2、点击进入实现类

image.png

3、再点击进入configuration.getMapper

image.png

4、点击进入mapperRegistry.getMapper方法

image.png

5、点击进入newInstance方法

代理工厂是如何创建实例的。怎么返回的代理对象直接能调用方法了呢?具体如下:
image.png

6、点击进入MapperProxy

进到_MapperProxyFactory类中的newInstance方法,又是通过_MapperProxy对象进行实例化来操作的。
image.png

image.png

7、通过newProxyInstance验证底层执行动态代理

下面这个是调用上面的 newInstance
image.png

8、点击进入mapperProxy方法

参数是mapperProxy,那么他的对象是什么呢,点进去看其类如何。
image.png

执行动态代理的时候,底层调用任何方法。都会去调用MapperProxy里面的invoke方法。
因为MapperProxy实现了InvocationHandler,当方法调用时,都会进到其里面的invoke方法。

4、invoke方法源码剖析

image.png

1、点击进入MapperProxy

image.png

2、点击进入execute方法

直接看到invoke方法。
image.png

3、点击进入executeForMany

因为当前接口的返回方法中的返回值 一个List集合。
image.png

4、具体还是sqlSession去操作

image.png

设计模式

https://blog.csdn.net/TNT_D/article/details/96832857?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.edu_weight

java 连接数据库实现增删改查的底层原理(源码)_TNT_D的…_CSDN博客


MyBatis的源码剖析例子https://blog.csdn.net/l1028386804/article/details/118079011