Spring/SpringBoot/SpringCloud Mybatis 执行流程

在后续分析Mybatis 流程中代码的可能会用到IDEA debug 技巧:

  1. 条件断点
    代码断点,右键 勾选弹窗 Condition : 写入表达式

在这里插入图片描述
在这里插入图片描述

  1. 回到上一步:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  2. Java动态代理实现 InvocationHandler接口:

package com.lvyuanj.core.test;import com.lvyuanj.core.model.User;
import org.apache.ibatis.annotations.Select;import java.util.List;public interface UserTestMapper {@Select("select * from t_user")public List<User> query();
}
package com.lvyuanj.core.test;import org.apache.ibatis.annotations.Select;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("query db:"+ method.getAnnotation(Select.class).value()[0]);return null;}}
package com.lvyuanj.core.test;import java.lang.reflect.Proxy;public class MyQueryTest {public static void main(String[] args) {Class[] clazz = {UserTestMapper.class};UserTestMapper userTestMapper = (UserTestMapper) Proxy.newProxyInstance(MyQueryTest.class.getClassLoader(), clazz, new MyInvocationHandler());userTestMapper.query();}
}
mybatis 核心FactoryBean

MapperScannerRegistrar
实现了ImportBeanDefinitionRegistrar 接口。 可以自动注入

MapperScannerConfigurer 实现 BeanDefinitionRegistryPostProcessor这个类
postProcessBeanDefinitionRegistry()中扫描注入mapper

MapperFactoryBean 实现了FactoryBean 也继承了SqlSessionDaoSupport 类;

Spring 管理MapperFactoryBean 的时候设置属性的时候初始化SqlSessionTemplate

public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);}}

需要的SqlSessionFactory 在AppConfig中定义,由于SqlSessionFactoryBean实现FactoryBean接口类,factoryBean.getObject(); 获取到真实的对象SqlSessionFactory

在创建对象的时候时候进行afterPropertiesSet(); 对象

 public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource());return factoryBean.getObject();
}

当开发者调用userMapper.selectAll() 方法的时候,由于userMapper是MapperFactoryBean 工厂bean创建的Bean的时候调用的是MapperFactoryBean.getObject(); 最终调用org.apache.ibatis.binding.MapperRegistry#getMapper(Class type, SqlSession sqlSession)
方法中调用 mapperProxyFactory.newInstance(sqlSession)

@Overridepublic T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");}try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}
protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);}public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);}

SqlSessionTemplate 是SqlSession 的实现类,

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator) {notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");notNull(executorType, "Property 'executorType' is required");this.sqlSessionFactory = sqlSessionFactory;this.executorType = executorType;this.exceptionTranslator = exceptionTranslator;this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),new Class[] { SqlSession.class }, new SqlSessionInterceptor());}
@Overridepublic <T> T selectOne(String statement, Object parameter) {return this.sqlSessionProxy.selectOne(statement, parameter);}/*** {@inheritDoc}*/@Overridepublic <K, V> Map<K, V> selectMap(String statement, String mapKey) {return this.sqlSessionProxy.selectMap(statement, mapKey);}/*** {@inheritDoc}*/@Overridepublic <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {return this.sqlSessionProxy.selectMap(statement, parameter, mapKey);}......

代理类

private class SqlSessionInterceptor implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);try {Object result = method.invoke(sqlSession, args);if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {  //是否启用事务管理,没有事务管理mybatis自己管理// force commit even on non-dirty sessions because some databases require// a commit/rollback before calling close()sqlSession.commit(true);}return result;} catch (Throwable t) {Throwable unwrapped = unwrapThrowable(t);if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {// release the connection to avoid a deadlock if the translator is no loaded. See issue #22closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);sqlSession = null;Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);if (translated != null) {unwrapped = translated;}}throw unwrapped;} finally {if (sqlSession != null) {closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);}}}}

开始涉及MyBatis SqlSession部分的一些机制,关于MyBatis sqlSession的一点整理,SqlSession主要是MyBatis定义的用于进行持久化操作的对象,对connection进行了包装。在上面Spring Transaction的机制中,我们获取到了connection,之后会首先调用SqlSessionUtils里面的getSession方法,判断当前的sqlSessionHolder以及是否存在事务锁定。

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator) {notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);SqlSession session = sessionHolder(executorType, holder);if (session != null) {return session;}LOGGER.debug(() -> "Creating a new SqlSession");session = sessionFactory.openSession(executorType);registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);return session;}

sessionFactory.openSession(executorType); sessionFactory上文中在sqlSessionFactoryBean 实现InitializingBean接口初始化的时候afterPropertiesSet() 方法被调用
this.sqlSessionFactory = buildSqlSessionFactory(); 执行是new DefaultSqlSessionFactory()对象。

  @Overridepublic SqlSession openSession(ExecutorType execType) {return openSessionFromDataSource(execType, null, false);}private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor = configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}

final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); 获取事务工厂类,第一次的时候new ManagedTransactionFactory();
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); 创建一个事务对象
final Executor executor = configuration.newExecutor(tx, execType);

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : executorType;Executor executor;if (ExecutorType.BATCH == executorType) {executor = new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {executor = new SimpleExecutor(this, transaction);}if (cacheEnabled) {executor = new CachingExecutor(executor);}executor = (Executor) interceptorChain.pluginAll(executor);return executor;}

UserMapper 初始化到调用链流程图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/794001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity:2D SpriteShape

1.1 简介 Sprite Shape 可以很灵活的更改sprite的轮廓。比如&#xff1a; 它由两部分组成&#xff1a;Sprite Shape Profile、Sprite Shape Controller&#xff0c;需要导入2D Sprite Shape Package. 1.1.1 Sprite导入要求 Texture Type - ‘Sprite (2D and UI)’.Sprite Mo…

备战蓝桥杯---刷二分与前缀和题

刷点题~ 1.二分多路归并算法 对于每一个技能&#xff0c;我们把它看成一个等差数列&#xff0c;我们把所有可能都放到一个集合里&#xff0c;排个序&#xff0c;取前m个大即可&#xff0c;现在考虑优化&#xff0c;假如m不是很大&#xff0c;我们直接用优先队列即可&#xff0…

python写文件怎么读出来

python中对文件的操作大概分为三步&#xff1a;打开文件、操作文件&#xff08;读、写、追加写入&#xff09;、关闭文件。 1、无论对文件做哪种操作&#xff0c;操作前首先要保证文件被打开了&#xff0c;即需要一个打开的操作。 例&#xff1a;open(XXX.txt) 打开文件的同…

python函数练习2

找出10000以内能被5或6整除&#xff0c;但不能被两者同时整除的数&#xff08;函数&#xff09; def func():for i in range(1,50):if (i % 5 0 or i % 6 0 ):if i % 5 0 and i % 6 0:continue #利用continue跳过能被5和6整除的数print(i) func()写一个方法&#xff0c;计算…

C#智慧手麻系统源码 医院手术麻醉系统源码 支持三甲医院评级需求 可提供演示

C#智慧手麻系统源码 医院手术麻醉系统源码 支持三甲医院评级需求 可提供演示 手术麻醉管理系统是应用于医院手术室、麻醉科室的计算机软件系统。该系统针对整个围术期&#xff0c;对病人进行全程跟踪与信息管理&#xff0c;自动集成病人HIS、LIS、RIS、PACS信息&#xff0c;采…

Autosar工具链配置 CanNM

CAN网络管理filter 网管报文范围0x600~0x6FF repeat message time 超时时间 接收到主动唤醒源&#xff0c;网管报文快发周期&#xff0c;次数&#xff1b;正常周期发送时间 网管报文btye设置&#xff1a;1、重复消息请求位设置 2、ECU地址 wait bus-sleep 定时设置以及网管报…

华为云1核2G免费使用一年

个人用户专享云服务器、云数据库产品每天上午9:30开抢&#xff0c;其他产品每天0点开放领取&#xff0c;企业用户所有产品每天0点开放领取&#xff1b; 云产品体验名额有限&#xff0c;领完即止。详情&#xff1a;https://www.vpspick.com/vps/591.html 通用入门型 T6 云服务…

2024免费Mac苹果解压压缩包软件BetterZip5

在2024年&#xff0c;对于Mac电脑用户来说&#xff0c;如果你想要无需解压就能快速查看压缩文档的内容&#xff0c;BetterZip是一个极佳的选择。这款软件不仅支持多种格式的压缩和解压&#xff0c;如zip、rar、7z、tar等&#xff0c;还具备丰富的功能和设置&#xff0c;包括预览…

QT-QPainter

QT-QPainter 1.QPainter画图  1.1 概述  1.1 QPainter设置  1.2 QPainter画线  1.3 QPainter画矩形  1.4 QPainter画圆  1.5 QPainter画圆弧  1.6 QPainter画扇形 2.QGradient  2.1 QLinearGradient线性渐变  2.2 QRadialGradient径向渐变  2.3 QConicalGr…

二、GitLab相关操作

GitLab相关操作 一、组、用户、项目管理1.创建组2.创建项目3.创建用户并分配组3.1 创建用户3.2 设置密码3.3 给用户分配组 二、拉取/推送代码1.配置ssh(第一次需要)1.1 创建一个空文件夹1.2 配置本地仓账号和邮箱1.3 生成ssh公钥密钥1.4 gitlab配置公钥 2.拉取代码3.推送代码3.…

C语言动态内存空间分配

1. 前言 在讲内存分配前&#xff0c;咱来聊一下为什么会有内存分配这个概念呢&#xff0c;大家都知道C语言当中是有着许多的数据类型&#xff0c;使用这些数据类型就会在内存上开辟其相对应的空间&#xff0c;那既然会开辟相应的空间&#xff0c;为什么还会有内存分配呢&#x…

springcloud基本使用三(搭建nacos)

window下安装nacos: 下载页面:Releases alibaba/nacos GitHuban easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. - Releases alibaba/nacoshttps://github.com/alibaba/nacos/releases…

基于卷积神经网络的中药识别(pytorch框架)【python源码+UI界面+前端界面+功能源码详解】

原作者链接&#xff1a;基于卷积神经网络的中药识别&#xff08;pytorch框架&#xff09;【python源码UI界面前端界面功能源码详解】_识别中药python-CSDN博客 //gitcode,gitee,飞桨&#xff0c;csdn&#xff0c;bilibili。几个有用网站&#xff0c;直接搜索即可&#xff0c;平…

主干网络篇 | YOLOv5/v7 更换骨干网络之 HGNetv2 | 百度新一代超强主干网络

本改进已融入到 YOLOv5-Magic 框架。 论文地址:https://arxiv.org/abs/2304.08069 代码地址:https://github.com/PaddlePaddle/PaddleDetection 中文翻译:https://blog.csdn.net/weixin_43694096/article/details/131353118 文章目录 HGNetv2网络结构1.1 主干网络1.2 颈部…

【Android】毫无耦合性,一个Item根布局搞定 item侧滑删除菜单,像IOS那样简单的使用侧滑删除。(1)

自定义ViewGroup实现侧滑删除简单&#xff0c;难得是还要同时 处理多指滑动的屏蔽&#xff0c;防止两个侧滑菜单同时出现&#xff0c;等等&#xff0c; 有办法将这些东西都用一个ViewGroup搞定么&#xff1f; 看本文如何巧用static类变量来解决这些矛盾冲突。 【2 预览】 那…

真快乐APP抢购源码实现

支持多个平台的自动 滑动验证码、选字验证码。缺点就是需要自己找一个验证码识别服务器,可以自己用python写一个,或者使用超级鹰(本篇教程就是使用它) 下面是实现源码 "ui"; Date.prototype.Format = function (fmt) {var o = {"M+": this.getMonth() …

2024年做抖音小店商家,最不该忽视的三个运营要点,一定要避开!

大家好&#xff0c;我是电商花花。 每一次平台规则的改变都深深的影响着我们无货源商家&#xff0c;我们只有在规则内行使&#xff0c;遵守规则&#xff0c;才能在安然无恙。 所以我们做抖音小店一定要及时关注平台的规则变化&#xff0c;以及整体的做店趋势。 只有这样才不…

App.vue触发axios报错及解决方案

App.vue触发axios报错及解决方案 修改根目录下vue.config.js文件 module.exports {publicPath: ./,assetsDir: assets,configureWebpack: {devServer: {client: {overlay: false}}} }重新npm run dev 搞定

十个排序算法

目录 冒泡排序(Bubble Sort) 选择排序(Select Sort) 插入排序&#xff08;InsertSort&#xff09; 希尔排序&#xff08;ShellSort&#xff09; 计数排序&#xff08;CountSort&#xff09; 快速排序&#xff08;QuickSort&#xff09; 归并排序&#xff08;Merge Sort&a…

Jenkins 安装部署

1、安装下载 官网地址&#xff1a;Jenkins 下载 war 包 1、前置环境 JDK 环境&#xff08;根据 Jenkins 版本不同&#xff0c;需要的 JDK 版本不同&#xff0c;目前需要 JDK11 的版本来支持&#xff09;Maven maven 官网下载压缩包 &#xff0c;并将其传输到服务器&#xf…