MyBatis源码(6)拦截器

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语句不会保存到一级缓存中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值