Spring/SpringBoot/SpringCloud Mybatis 执行流程

news2024/12/27 14:04:30

在后续分析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 {

	@Override
	public 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)

@Override
  public 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());
  }
@Override
  public <T> T selectOne(String statement, Object parameter) {
    return this.sqlSessionProxy.selectOne(statement, parameter);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
    return this.sqlSessionProxy.selectMap(statement, mapKey);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
    return this.sqlSessionProxy.selectMap(statement, parameter, mapKey);
  }
  
  ......

代理类

private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public 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 #22
          closeSqlSession(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()对象。

  @Override
  public 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.coloradmin.cn/o/1571065.html

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

相关文章

MAX7219驱动数码管学习记录(有源码)

一、7219datasheet阅读 1.引脚定义&#xff1a; 重点介绍5个引脚 1.DIN&#xff1a; 串行数据总线输入引脚&#xff0c;每个时钟的上升沿将数据移入至芯片内部的移位寄存器中 2.DIG0-DIG7: 共阴极管的GND连接的便是DIG0-7,该引脚起作用时&#xff0c;便输出低电平&#xff0c…

SSM学习——Spring JDBC

Spring JDBC 概念 Spring的JDBC模块负责数据库资源管理和错误处理&#xff0c;简化了开发人员对数据库的操作。 Spring JDBC通过配置数据源和JDBC模板来配置。 针对数据库操作&#xff0c;Spring框架提供了JdbcTemplate类&#xff0c;它是Spring框架数据抽象层的基础&#…

【学习】渗透测试有哪些重要性

随着信息技术的迅猛发展&#xff0c;网络安全问题日益凸显。渗透测试作为网络安全防御的重要手段之一&#xff0c;旨在模拟黑客攻击&#xff0c;发现并修复潜在的安全漏洞&#xff0c;提高网络系统的安全性。本文将介绍渗透测试的概念、重要性、实施步骤及实践案例&#xff0c;…

echarts快速入门

文章目录 一、echarts下载1.1、下载说明1.2、使用说明 二、绘制一个简单图表 一、echarts下载 echarts是百度研发团队开发的一款报表视图JS插件&#xff0c;功能十分强大&#xff0c;可在echart官网下载源码&#xff08;一个echarts.min.js文件&#xff09;进行使用。 1.1、…

Star GAN论文解析

论文地址&#xff1a;https://arxiv.org/pdf/1912.01865v1.pdf https://openaccess.thecvf.com/content_cvpr_2018/papers/Choi_StarGAN_Unified_Generative_CVPR_2018_paper.pdf 源码&#xff1a;stargan项目实战及源码解读-CSDN博客 1. 概述 在传统方法中&#x…

R语言技能 | 不同数据类型的转换

原文链接&#xff1a;R语言技能 | 不同数据类型的转换 本期教程 写在前面 今天是4月份的第一天&#xff0c;再过2天后再一次迎来清明小假期。木鸡大家是否正常放假呢&#xff1f; 我们在使用R语言做数据分析时&#xff0c;会一直对数据进行不同类型的转换&#xff0c;有时候…

揭秘视觉Transformer之谜,TokenTM新法,全面提升模型解释性能

引言&#xff1a;揭示视觉Transformer的解释挑战 在计算机视觉应用中&#xff0c;Transformer模型的流行度迅速上升&#xff0c;但对其内部机制的后置解释仍然是一个未探索的领域。视觉Transformers通过将图像区域表示为转换后的tokens&#xff0c;并通过注意力权重将它们整合起…

一篇文章带你掌握二叉树(附带二叉树基本操作完整代码演示,和两种思路)

【本长内容】 1. 掌握树的基本概念 2. 掌握二叉树概念及特性 3. 掌握二叉树的基本操作 4. 完成二叉树相关的面试题练习 1. 树形结构 1.1 概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是…

RK3568平台 Uart驱动框架

一.TTY子系统 在Linux kernel中&#xff0c;tty驱动不像于spi&#xff0c;iic等那么架构简单&#xff0c;它是一个庞大的系统&#xff0c;它的框架大体如下图一。我们作为普通的驱动开发移植人员&#xff0c;不会从零写tty驱动&#xff0c;一般都是厂家根据现有的tty驱动和自家…

SpringBoot整合MyBatis四种常用的分页方式

目录 方式1 一、准备工作 1. 创建表结构 2. 导入表数据 3. 导入pom.xml依赖 4. 配置application.yml文件 5. 创建公用的实体类 项目结构 2. 创建controller层 3. 创建service层 4. 创建mapper层 5. 创建xml文件 6. 使用postman进行测试&#xff0c;测试结果如下…

基于JAVA+SpringBoot+Vue的前后端分离的大学健康档案管理系统

一、项目背景介绍&#xff1a; 随着社会的发展和科技的进步&#xff0c;人们越来越重视健康问题。大学作为培养人才的摇篮&#xff0c;学生的健康状况直接影响到国家的未来。然而&#xff0c;传统的大学健康档案管理方式存在诸多问题&#xff0c;如信息不透明、数据分散、更新不…

从零开始为香橙派orangepi zero 3移植主线linux——2.kernel + rootfs

从零开始为香橙派orangepi zero 3移植主线linux——2.kernel rootfs 参考文章&#xff1a;一、linux kernel移植二、根文件系统2.1 buildroot构建1.修改toolchain下的交叉编译链2.修改系统配置3.去除内置kernel和uboot编译4.添加rootfs.tar格式的输出 2.2 ubuntu-base移植 三、…

WebAuthn:更好地保护线上敏感信息

1. 引言 2023年知乎博客 WebAuthn: 真正的无密码身份认证 总结得很赞。 在数字时代&#xff0c;密码已成为人们日常生活和在线活动中不可或缺的一部分。尽管互联网已经发展了 20 多年&#xff0c;许多方面都有了巨大的改进&#xff0c;但只有密码&#xff0c;还是 20 年前的用…

【数据结构】--- 探索栈和队列的奥秘

关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა &#x1f4a1;个人主页&#xff1a;9ilk &#x1f4a1;专栏&#xff1a;数据结构之旅 上回我们学习了顺序表和链表&#xff0c;今天博主来讲解两个新的数据结构 — 栈和队列 &#xff0c; 请放心食用 文章目录 &#x1f3e0; 栈&#x1…

牛客 2024春招冲刺题单 ONT102 牛牛的果实排序【simpe 要知道如何判断是否是质数 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/975a263e2ae34a669354e0bd64db9e2a 核心 需要牢牢记住下面的代码//判断是否为质数public boolean isPrime(int n){if(n1) return false;if(n2 || n3) return true;if(n%6!1 && n%6!5) return false; /…

C++(语法以及易错点2)

1.内联函数 1.1 概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调 用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 ​int ADD(int a,int b) {return ab; }​ 1.2 特性 1. inline是一种以空间换时间…

spring security6重写登陆验证

spring security的认证流程 2. 从文档上可以看出来&#xff0c;UsernamePasswordAuthenticationFilter和AuthenticationManager是认证的关键步骤&#xff0c;/login传过来的username和password由UsernamePasswordAuthenticationFilter接收处理成UsernamePasswordAuthenticatio…

设计模式总结-组合模式

组合设计模式 模式动机模式定义模式结构组合模式实例与解析实例一&#xff1a;水果盘实例二&#xff1a;文件浏览 更复杂的组合总结 模式动机 对于树形结构&#xff0c;当容器对象&#xff08;如文件夹&#xff09;的某一个方法被调用时&#xff0c;将遍历整个树形结构&#x…

基于SSM的品牌银饰售卖平台(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的品牌银饰售卖平台&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring …

LeetCode - 边积分最高的节点

2374. 边积分最高的节点 这是一个有向图&#xff0c;且每个节点都只有一条出边&#xff0c;指向0的边有1&#xff0c;2&#xff0c;3&#xff0c;4 10&#xff0c; 指向7的有5&#xff0c;6 11. 我们只需要一次遍历就可以解决&#xff0c;先搞一张哈希表&#xff0c;k存节点…