首页 > 其他分享 >Spring/SpringBoot/SpringCloud Mybatis 执行流程

Spring/SpringBoot/SpringCloud Mybatis 执行流程

时间:2024-04-05 09:33:18浏览次数:23  
标签:return SpringBoot Spring executorType SqlSession sqlSession SpringCloud new publ

在后续分析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 初始化到调用链流程图

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

标签:return,SpringBoot,Spring,executorType,SqlSession,sqlSession,SpringCloud,new,publ
From: https://blog.csdn.net/lvyuanj/article/details/137392088

相关文章

  • Spring 注解编程之 AnnotationMetadata
    Spring注解编程之AnnotationMetadata这篇文章我们主要深入AnnotationMetadata,了解其底层原理。Spring版本为5.1.8-RELEASEAnnotationMetadata结构使用IDEA生成AnnotationMetadata类图,如下:AnnotationMetadata存在两个实现类分别为StandardAnnotationMeta......
  • Java项目:基于Springboot+vue实现的医院住院管理系统设计与实现(源码+数据库+开题报告+
    一、项目简介本项目是一套基于Springboot+vue实现的医院住院管理系统设包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。项目都经过严格调试,eclipse或者idea确保可以运行!该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值......
  • 一键部署 SpringCloud 微服务,这套流程值得学习一波儿!
    文章目录前言1、开发者将代码PUSH到Git2、通过Jenkins部署,自动到Git上PULL代码2.1、配置SSH-KEY2.1.1、生成/添加SSH公钥2.1.2、将公钥配置到git平台2.1.3、测试2.2、配置Jenkins的pipeline自动clone代码2.2.1、Jenkins创建任务2.2.2、测试拉代码流程3、通过maven......
  • 【附源码】计算机毕业设计智慧社区团购系统的设计(java+springboot+mysql+mybatis+论文
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义随着互联网技术的发展和普及,社区团购作为一种新兴的电商模式,正逐渐改变着人们的购物习惯。然而,传统的社区团购系统存在着一些问题,如信息不透明、效率低下、用户体......
  • 【附源码】计算机毕业设计游戏分享网站(java+springboot+mysql+mybatis+论文)
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义随着互联网技术的发展,游戏行业正逐渐向数字化、网络化方向发展。越来越多的游戏玩家开始通过网络分享自己的游戏心得、攻略和视频等内容,形成了一个庞大的游戏分享......
  • 【附源码】计算机毕业设计在线药品销售系统(java+springboot+mysql+mybatis+论文)
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义随着互联网技术的不断发展,人们的生活方式也在逐渐改变。在药品销售领域,传统的线下药店已经不能满足人们的需求。在线药品销售系统应运而生,为人们提供了一个更加便......
  • 【附源码】计算机毕业设计中医保健网站(java+springboot+mysql+mybatis+论文)
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义中医保健网站是一个提供中医养生、保健知识的在线平台。随着人们生活水平的提高,越来越多的人开始关注自己的身体健康,而中医作为中国传统医学的一种,具有悠久的历史......
  • 【附源码】计算机毕业设计长护险管理系统的设计与实现(java+springboot+mysql+mybatis+
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义长护险管理系统是一种基于互联网技术的信息化管理平台,旨在提高长期护理保险(简称“长护险”)的管理效率和服务质量。随着人口老龄化的加剧和社会保障体系的完善,长护......
  • 基于springboot实现社区医院信息平台系统项目【项目源码+论文说明】
    基于springboot实现社区医院信息平台系统演示摘要随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了社区医院信息平台的开发全过程。通过分析社区医院信息平台管理的不足,创建了一个计算机管理社区医院信息平台的方案。文章介......
  • 基于springboot实现足球青训俱乐部管理后台系统项目【项目源码+论文说明】
    基于springboot实现足球青训俱乐部管理系统演示摘要随着社会经济的快速发展,人们对足球俱乐部的需求日益增加,加快了足球健身俱乐部的发展,足球俱乐部管理工作日益繁忙,传统的管理方式已经无法满足足球俱乐部管理需求,因此,为了提高足球俱乐部管理效率,足球俱乐部管理后台系统应......