MyBatis 源码学习7——SqlSession执行Mapper过程(下)

三、Mapper方法调用过程详解

SqlSession对象的getMapper()方法获取一个动态代理对象,然后通过代理对象调用方法,即执行MapperProxy类的invoke()方法

在这里插入图片描述

详细看下MapperProxy类的invoke()方法实现:

1.如果方法是从Object类继承的,不做任何处理,

2.如果是Mapper接口中定义的方法,调用cachedMapperMethod()方法获取一个MapperMethod对象。

其中,cachedMapperMethod()方法中对MapperMethod对象做了缓存,

1.首先从缓存中获取,

2.如果获取不到,则创建MapperMethod对象,然后添加到缓存中,这是享元思想的应用,避免频繁创建和回收对象。
在这里插入图片描述

MapperMethod类
对Mapper方法相关信息的封装,通过MapperMethod能够很方便地获取SQL语句的类型、方法的签名信息等。下面是MapperMethod类的构造方法:
在这里插入图片描述

在MapperMethod构造方法中创建了一个SqlCommand对象和一个MethodSignature对象:
SqlCommand对象用于获取SQL语句的类型(UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH)、Mapper的Id等信息;

SqlCommand构造方法:
在这里插入图片描述

1.调用resolveMappedStatement()方法,根据Mapper接口的完全限定名和方法名获取对应的MappedStatement对象,

2.然后通过MappedStatement对象获取SQL语句的类型和Mapper的Id。

resolveMappedStatement()方法的实现:
在这里插入图片描述

1.首先将接口的完全限定名和方法名进行拼接,作为Mapper的Id从Configuration对象中查找对应的MappedStatement对象

2.如果查找不到,则判断该方法是否是从父接口中继承的,如果是,就以父接口作为参数递归调用resolveMappedStatement()方法,若找到对应的MappedStatement对象,则返回该对象,否则返回null。

MethodSignature对象用于获取方法的签名信息,例如Mapper方法的参数名、参数注解等信息。

MethodSignature类的构造方法:
在这里插入图片描述

1.获取Mapper方法的返回值类型,具体是哪种类型,通过boolean类型的属性进行标记。
例如,当返回值类型为void时,returnsVoid属性值为true,当返回值类型为List时,将returnsMap属性值设置为true。
在这里插入图片描述

2.记录RowBounds参数位置,用于处理后续的分页查询,同时记录ResultHandler参数位置,用于处理从数据库中检索的每一行数据。

3.创建ParamNameResolver对象。ParamNameResolver对象用于解析Mapper方法中的参数名称及参数注解信息。

ParamNameResolver构造方法中完成了Mapper方法参数的解析过程,代码如下:

ParamNameResolver构造方法中:
在这里插入图片描述

1.对所有Mapper方法的所有参数信息进行遍历,

2.首先判断参数中是否有**@Param注解,如果包含@Param注解,就从注解中获取参数名称,如果参数中没有@Param注解,
就根据MyBatis主配置文件中的
useActualParamName参数**确定是否获取实际方法定义的参数名称,若useActualParamName参数值为true,则使用方法定义的参数名称。

3.解析完毕后,将参数信息保存在一个不可修改的names属性中,该属性是一个SortedMap<Integer, String>类型的对象。

到此,整个MapperMethod对象的创建过程已经完成。接下来介绍Mapper方法的执行。回到MapperProxy的invoke()方法,MapperMethod调用了execute()方法,用于执行SQL命令:

详细看下在execute()方法的实现:
在这里插入图片描述

1.首先根据SqlCommand对象获取SQL语句的类型,

2.然后根据SQL语句的类型调用SqlSession对象对应的方法。例如,当SQL语句类型为INSERT时,通过SqlCommand对象获取Mapper的Id,然后调用SqlSession对象的insert()方法。

MyBatis通过动态代理将Mapper方法的调用转换成通过SqlSession提供的API方法完成数据库的增删改查操作,即旧的iBatis框架调用Mapper的方式。

四、SqlSession执行Mapper过程

SqlSession接口只有一个默认的实现,即DefaultSqlSession,下面以SELECT语句为例介绍SqlSession执行Mapper的过程:
在这里插入图片描述

DefaultSqlSession的selectList()方法中:
在这里插入图片描述

1.首先根据Mapper的Id从Configuration对象中获取对应的MappedStatement对象,
2.然后以MappedStatement对象作为参数,调用Executor实例的query()方法完成查询操作。

详细看下BaseExecutor类对query()方法的实现:
在这里插入图片描述

1.首先从MappedStatement对象中获取BoundSql对象,BoundSql类中封装了经过解析后的SQL语句及参数映射信息。

2.然后创建CacheKey对象,该对象用于缓存的Key值。接着调用重载的query()方法,
在这里插入图片描述
3.在重载的query()方法中,首先从MyBatis一级缓存中获取查询结果,如果缓存中没有,则调用BaseExecutor类的queryFromDatabase()方法从数据库中查询。

在这里插入图片描述
在queryFromDatabase()方法中,调用doQuery()方法进行查询,然后将查询结果进行缓存(doQuery()是一个模板方法,由BaseExecutor子类实现)。

SimpleExecutor类的doQuery()方法中的实现:
在这里插入图片描述

1.首先调用Configuration对象的newStatementHandler()方法创建StatementHandler对象。newStatementHandler()方法返回的是RoutingStatementHandler的实例。
在RoutingStatementHandler类中,会根据配置Mapper时statementType属性指定的StatementHandler类型创建对应的StatementHandler实例进行处理,例如statementType属性值为SIMPLE时,则创建SimpleStatementHandler实例。

2.调用SimpleExecutor类的prepareStatement()方法创建JDBC中的Statement对象,然后为Statement对象设置参数操作。

3.Statement对象初始化工作完成后,再调用StatementHandler的query()方法执行查询操作。

看一下SimpleExecutor类中prepareStatement()方法的实现:
在这里插入图片描述

1.首先获取JDBC中的Connection对象,

2.然后调用StatementHandler对象的prepare()方法创建Statement对象,

3.接着调用StatementHandler对象的parameterize()方法(parameterize()方法中会使用ParameterHandler为Statement对象设置参数)。

MyBatis的StatementHandler接口有几个不同的实现类,分别为SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler。MyBatis默认情况下会使用PreparedStatementHandler与数据库交互。

PreparedStatementHandler类query()方法的实现:
在这里插入图片描述

1.首先调用PreparedStatement对象的execute()方法执行SQL语句,

2.然后调用ResultSetHandler的handleResultSets()方法处理结果集。ResultSetHandler只有一个默认的实现,即DefaultResultSetHandler类。

DefaultResultSetHandler类的handleResultSets()方法的实现:
在这里插入图片描述
1.首先从Statement对象中获取ResultSet对象,然后将ResultSet包装为ResultSetWrapper对象,通过ResultSetWrapper对象能够更方便地获取数据库字段名称以及字段对应的TypeHandler信息。

2.获取Mapper SQL配置中通过resultMap属性指定的ResultMap信息,一条SQL Mapper配置一般只对应一个ResultMap。

3.调用handleResultSet()方法对ResultSetWrapper对象进行处理,将结果集转换为Java实体对象,然后将生成的实体对象存放在multipleResults列表中。

4.调用collapseSingleResultList()方法对multipleResults进行处理,如果只有一个结果集,就返回结果集中的元素,否则返回多个结果集。

到此,MyBatis如何通过调用Mapper接口定义的方法执行注解或者XML文件中配置的SQL语句这一整条链路介绍完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值