首页 > 编程语言 >MyBatis源码(6)拦截器

MyBatis源码(6)拦截器

时间:2024-08-25 14:51:32浏览次数:8  
标签:拦截器 对象 调用 update 源码 MyBatis StatementHandler 方法

1、目标

本文的主要目标是学习MyBatis拦截器的源码,本文将以插入操作为例debug拦截器相关的源码

2、拦截器源码分析

调用mapper接口的insert插入记录方法,会调用SqlSession对象的insert方法

在这里插入图片描述

SqlSession执行insert方法

在这里插入图片描述

Spring容器会创建SqlSessionTemplate对象,为了实现插入操作,可以分为三步:

(1)创建Executor执行器对象和SqlSession对象

(2)反射调用update方法完成插入操作

(3)SqlSession执行commit方法提交事务

3、创建Executor执行器对象和SqlSession对象

在这里插入图片描述

它会分别创建Executor执行器对象和SqlSession对象

3.1 newExecutor方法

在这里插入图片描述

执行器链会调用pluginAll方法将拦截器创建JDK动态代理对象

在这里插入图片描述

遍历所有的拦截器,每个拦截器都执行plugin方法

在这里插入图片描述

plugin方法会调用Plugin的wrap这个静态方法,此时由于没有拦截Executor执行器的拦截器,因此不会创建JDK动态代理对象

4、反射调用update方法完成插入操作

在这里插入图片描述

SqlSession对象会反射调用insert方法,其中参数是mapper接口方法的入参,这个方法会调用update方法

在这里插入图片描述

它会调用BaseExecutor执行器的update方法进行插入操作,它会调用doUpdate方法

在这里插入图片描述

最终会调用SimpleExecutor执行器的doUpdate方法,它会执行插入操作,具体是:

(1)newStatementHandler方法创建RoutingStatementHandler对象

(2)prepareStatement方法创建Stetement对象

(3)StetementHandler对象的update方法

4.1 newStatementHandler方法创建RoutingStatementHandler对象

在这里插入图片描述

先创建RoutingStatementHandler对象,然后调用拦截器链的pluginAll方法生成JDK动态代理对象

在这里插入图片描述

由于存在StatementHandler对象的拦截器,因此会调用Proxy.newProxyInstance方法创建RoutingStatementHandler对象的JDK动态代理对象

在这里插入图片描述

返回的StatementHandler对象是基于StatementHandler接口的JDK动态代理对象,其中三个拦截器对象是层层嵌套的,形成一个拦截器链

4.2 prepareStatement方法创建Stetement对象

在这里插入图片描述

prepareStatement方法会先调用StatementHandler对象的prepare方法创建Statement对象,然后调用StatementHandler对象的parameterize方法给参数赋值

4.2.1 prepare方法

在这里插入图片描述

由于这个拦截器是拦截StatementHandler对象的prepare方法,因此先走到这个拦截器,然后调用invocation.proceed方法会执行StatementHandler对象的prepare方法

在这里插入图片描述

BaseStatementHandler对象的prepare方法会实例化Statement对象

在这里插入图片描述

实例化Statement对象的方法会根据BoundSql对象中的sql属性得到sql语句并实例化Statement对象,因此最好在StatementHandler对象的prepare方法之前修改sql语句

4.2.2 parameterize方法

在这里插入图片描述

由于这个拦截器拦截的是StatementHandler对象的parameterize方法,因此会先走到这个拦截器中,然后执行invocation.proceed方法会调用StatementHandler对象的parameterize方法

在这里插入图片描述

它会调用ParameterHandler对象的setParameters方法完成参数赋值的功能

在这里插入图片描述

DefaultParameterHanlder对象会先根据BoundSql对象的parameterMappings这个List集合的大小n,然后设置PreparedStatement对象的参数值对应的下标是从1开始到n

在这里插入图片描述

执行PreparedStatement对象的setString方法会设置下标是i,参数值是parameter,用setString方法可以在字符串参数值加上单引号,防止sql注入

在这里插入图片描述

因此,在拦截器中会调用PreparedStatement对象的setString等方法

4.2.3 结果

在这里插入图片描述

最终将下标和对应的参数值保存在PreparedStatementLogger对象的columnMap中

4.3 StetementHandler对象的update方法

在这里插入图片描述

调用StatementHandler对象的update方法,入参是Statement对象

在这里插入图片描述

由于这个拦截器拦截的是StatementHandler对象的update方法,因此会先走这个拦截器,然后执行invocation.proceed方法会调用StatementHandler对象的update方法

4.3.1 update方法

在这里插入图片描述

PreparedStatementHandler对象的update方法会调用PreparedStatement对象的execute方法执行JDBC的插入操作,并返回更新数据库的行数rows

5、SqlSession执行commit方法提交事务

在这里插入图片描述

SqlSession对象的commit方法会清除一级缓存,因此默认情况下SpringBoot整合MyBatis每次调用sql语句不会保存到一级缓存中

标签:拦截器,对象,调用,update,源码,MyBatis,StatementHandler,方法
From: https://blog.csdn.net/weixin_43823462/article/details/141526773

相关文章