1、@ComponentScan basePackages与value: 用于指定包的路径,进行扫描 basePackageClasses: 用于指定某个类的包的路径进行扫描 nameGenerator: bean的名称的生成器 useDefaultFilters: 是否开启对@Component,@Repository,@Service,@Controller的类进行检测 url: https://blog.csdn.net/u012326462/article/details/82765485

2、@ImportResource注解 用于导入 Spring 的 xml 配置文件,让该配置文件中定义的 bean 对象加载到Spring容器中。 参考链接:https://blog.csdn.net/lzb348110175/article/details/105148214

3、 引入依赖

<dependency> <groupId>org.mybatis.spring.boot</groupId>

<artifactId>mybatis-spring-boot-starter</artifactId> </dependency>

在上述BeanFactory的后置处理器中就会读取mybatis-spring-boot-autoconfigure-***.jar包中的spring.factories文件 /org/mybatis/spring/boot/mybatis-spring-boot-autoconfigure/2.1.0/mybatis-spring-boot-autoconfigure-2.1.0.jar!/META-INF/spring.factories org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

<!-- 通过扫描的模式,扫描目录在mapper目录下,所有的mapper都继承SqlMapper接口的接口, 这样一个bean就可以了-->

@MapperScan和@Mapper都可以,@Mapper每个接口都要写 为什么没有加@MapperScan注解也可以扫描mapper接口 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.hsjry.convert.dal.dao.mapper.**" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean>

扫描调用栈 1.org.mybatis.spring.annotation.MapperScannerRegistrar#registerBeanDefinitions(org.springframework.core.annotation.AnnotationAttributes, org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.String)

2.org.mybatis.spring.annotation.MapperScannerRegistrar#registerBeanDefinitions(org.springframework.core.annotation.AnnotationAttributes, org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.String) 声明要注册的对象 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);

3. 向这个注册中心注册一个新的 bean 定义 要用到BeanDefinitionRegistry org.springframework.beans.factory.support.BeanDefinitionRegistry#registerBeanDefinition

4.org.mybatis.spring.mapper.MapperScannerConfigurer#postProcessBeanDefinitionRegistry

5.org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan

6.org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan @return 注册的 bean set集 Set<BeanDefinitionHolder>

7.org.mybatis.spring.mapper.ClassPathMapperScanner#doScan

8.ClassPathMapperScanner extends ClassPathBeanDefinitionScanner

9.扫描到mapper接口了 org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions

10.ClassPathMapperScanner#processBeanDefinitions // 处理BeanDefinitions // 入参的beanDefinitions是从mapper接口产生的 private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { GenericBeanDefinition definition; for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); // the mapper interface is the original class of the bean // but, the actual class of the bean is MapperFactoryBean // 是为了创建mapperFactoryBean对象时,给mapperInterface赋值 definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // 设置beanClass = mapperFactoryBean.class definition.setBeanClass(this.mapperFactoryBean.getClass()); ....... // 按类型注入,作用是在创建MapperFactoryBean对象时,通过set方法按类型实现装配 definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } } }

11.org.mybatis.spring.mapper.MapperFactoryBean#getObject public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> 很多都是在spring做扩展

12.org.apache.ibatis.session.SqlSession#getMapper interface

13.org.mybatis.spring.SqlSessionTemplate#getMapper

14.org.apache.ibatis.session.Configuration#getMapper 这个就是SqlSession接口的方法

15.org.apache.ibatis.binding.MapperRegistry#getMapper

16.org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)

17.org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.binding.MapperProxy<T>),在这个方法中,使用JDK动态代理,创建代理对象,该代理对象就是我们Service层的代码中注入的对象 dao层接口。

二.MyBatis的SqlSession是非线程安全的,那Spring的SqlSessionTemplate是怎么解决的这个问题?

1.org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke

2.org.mybatis.spring.SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator):

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {

notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED); notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

//从事务同步管理器中取sqlSession

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; }

MyBatis 方法调用路由到从 Spring 的事务管理器获得的正确 SqlSession 事务同步管理器可以认为是一个ThreadLocal的map,这样同一个线程在使用SqlSessionTemplate多次对数据库操作的时候,取到的是同一个SqlSession;而不同的线程取到的是不同的SqlSession,所以说SqlSessionTemplate是线程安全的。

三 MyBatis怎么跟Spring声明式事务配合完成的数据库事务内的增删改查操作?

1.设置数据库连接的自动提交为false

2.通过这个数据库连接进行sql语句执行

3.异常回滚或者提交 以上三步中的1和3是Spring声明式事务做的,2是MyBatis做的,它们是怎么配合的呢?其实只需要保证1、2、3这三步中获取到的是同一个数据库连接就好,其实也是通过事务同部管理器这个ThreadLocal的map来实现的 1.org.springframework.transaction.interceptor.TransactionInterceptor#invoke>>

TransactionInterceptor extends TransactionAspectSupport

//存在在threadLocal里面去

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction 》》

org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo#bindToThread

2.org.mybatis.spring.SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator)

去spring 管理的事务同步管理器中拿sqlSession 拿不到就拿传进来的SqlSessionFactory去开一个session org.apache.ibatis.session.SqlSessionFactory#openSession(org.apache.ibatis.session.ExecutorType) >>> org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession(org.apache.ibatis.session.ExecutorType)>>>

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource>>>

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {

Transaction tx = null; try { final Environment environment = configuration.getEnvironment();

//创建的是 就是TransactionFactory实现类org.apache.ibatis.transaction.managed.ManagedTransactionFactory

//从环境配置中拿到的是org.apache.ibatis.transaction.TransactionFactory final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);

// autoCommit是false

//new org.mybatis.spring.transaction.SpringManagedTransaction 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();

}

}

3.org.mybatis.spring.transaction.SpringManagedTransaction#getConnection>>

org.mybatis.spring.transaction.SpringManagedTransaction#openConnection>>

org.springframework.jdbc.datasource.DataSourceUtils#getConnection>>

org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

四.springboot整合mybatis是怎么做到不用配置mybatis-config.xml的呢?

1.https://mybatis.org/mybatis-3/configuration.html mybatis-config.xml属性参考官网文档

2.用mybatis-config.xml配置文件 org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.Reader, java.lang.String, java.util.Properties)》》

//解析配置文件得到Configuration对象,得到DefaultSqlSessionFactory对象

org.apache.ibatis.session.SqlSessionFactoryBuilder#build(org.apache.ibatis.session.Configuration)》》

org.apache.ibatis.builder.xml.XMLConfigBuilder#parse》》

org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration 这里的顺序有依赖关系 properties先解析 后面environments,databaseIdProvider都可以用到

properties》settings》typeAliases》plugins》objectFactory》objectWrapperFactory》reflectorFactory》environments》databaseIdProvider》typeHandlers》mappers

3.springboot自动配置 引入依赖 <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> 要使配置生效两种方式

1、@EnableConfigurationProperties(MybatisProperties.class)org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration @EnableConfigurationProperties 注解的作用是:让使用了 @ConfigurationProperties 注解的类生效,并且将该类注入到 IOC 容器中,交由 IOC 容器进行管理

2、使用 @ConfigurationProperties + @Component 注解 用于自定义默认设置的配置对象。如果指定了 {@link #configLocation},则 * 不使用此属性

@NestedConfigurationProperty private Configuration configuration; 表示 {@link ConfigurationProperties} 对象中的字段应该被视为 * 如果它是嵌套类型。此注释与实际绑定 * 进程无关,但它被 {@code spring-boot-configuration-processor} 用作提示 * 字段未绑定为单个值。指定时,*为该字段创建一个嵌套组,并获取其类型。 * <p> * 这对collections and maps没有影响,因为这些类型是自动识别的 前缀是mybatis加@NestedConfigurationProperty 我们就可以表明它是嵌套组了 可以在配置设置这个对象里面的值

mybatis:

  configuration:

    cache-enabled:

@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })

public class MybatisAutoConfiguration implements InitializingBean {

提示应该在其他指定的自动配置类之后应用 {@link EnableAutoConfiguration 自动配置} 这个注解表示DataSourceAutoConfiguration MybatisLanguageDriverAutoConfiguration要在MybatisAutoConfiguration 后执行 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration》》

org.springframework.boot.autoconfigure.jdbc.DataSourceProperties 前缀是spring.datasource 动态代理

spring整合mybatis的debug的步骤:

org.apache.ibatis.session.defaults.DefaultSqlSession@14d6f58f

org.apache.ibatis.session.SqlSession#insert(java.lang.String, java.lang.Object)

org.apache.ibatis.binding.MapperProxy#invoke》》

org.apache.ibatis.binding.MapperMethod#execute》》

org.mybatis.spring.SqlSessionTemplate#insert(java.lang.String, java.lang.Object)》》

org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke》》

org.apache.ibatis.session.defaults.DefaultSqlSession#insert(java.lang.String, java.lang.Object)》》也是通过代理生成的,传统的操作是直接工厂模式new

org.apache.ibatis.session.defaults.DefaultSqlSession#update(java.lang.String, java.lang.Object)》》

org.apache.ibatis.plugin.Plugin#invoke》》

org.apache.ibatis.executor.CachingExecutor#update》》这里面不用创建缓存只有query才需要

org.apache.ibatis.executor.BaseExecutor#update》》

org.apache.ibatis.executor.BaseExecutor#doUpdate》》

org.apache.ibatis.executor.SimpleExecutor#doUpdate》》

org.apache.ibatis.executor.statement.SimpleStatementHandler#update》》

java.sql.Statement#execute(java.lang.String)

jdbc里内容了

@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}

Plugin里的invoke方法

一堆代理

springboot整合mybatis以及mybatis源码分析的更多相关文章

  1. Springboot中mybatis执行逻辑源码分析

    Springboot中mybatis执行逻辑源码分析 在上一篇springboot整合mybatis源码分析已经讲了我们的Mapper接口,userMapper是通过MapperProxy实现的一个动 ...

  2. MyBatis 之 SqlSessionManager 源码分析

    MyBatis 的 4 个基本构成: SqlSessionFactoryBuilder(构造器): 根据配置信息或者代码来生成 SqlSessionFactory(工厂接口) SqlSessionFa ...

  3. MyBatis架构与源码分析<资料收集>

    1.架构与源码分析 :https://www.cnblogs.com/luoxn28/p/6417892.html .https://www.cnblogs.com/wangdaijun/p/5296 ...

  4. springboot Properties加载顺序源码分析

    关于properties: 在spring框架中properties为Environment对象重要组成部分, springboot有如下几种种方式注入(优先级从高到低): 1.命令行 java -j ...

  5. SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)

    SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringApplicat ...

  6. SpringBoot与Mybatis整合方式01(源码分析)

    前言:入职新公司,SpringBoot和Mybatis都被封装了一次,光用而不知道原理实在受不了,于是开始恶补源码,由于刚开始比较浅,存属娱乐,大神勿喷. 就如网上的流传的SpringBoot与Myb ...

  7. Mybatis原理及源码分析

    什么是Mybatis? Mybatis是一个半自动化的持久层框架. Mybatis可以将向PreparedStatement中的输入参数自动进行映射(输入映射),将结果集映射成Java对象(输出映射) ...

  8. mybatis 学习四 源码分析 mybatis如何执行的一条sql

    总体三部分,创建sessionfactory,创建session,执行sql获取结果 1,创建sessionfactory      这里其实主要做的事情就是将xml的所有配置信息转换成一个Confi ...

  9. 学习SpringBoot整合SSM三大框架源码之SpringBoot

    Spring Boot源码剖析 一.Spring Boot 项目的启动入口流程分析 Spring Boot项目的启动入口main线程上有一个@SpringBootApplication( @Confi ...

  10. SpringBoot @ConditionalOnBean、@ConditionalOnMissingBean注解源码分析与示例

    前言: Spring4推出了@Conditional注解,方便程序根据当前环境或者容器情况来动态注入bean,对@Conditional注解不熟悉的朋友可移步至 Spring @Conditional ...

随机推荐

  1. idea debug---启动超级慢,提示”Method breakpoints may dramatically slow down debugging“的解决办法

    https://blog.csdn.net/hanqing456/article/details/111878982 1.问题项目正常启动的时候没问题,debug模式就卡住了,很久不动.我推测是哪个断 ...

  2. 亲测有效! Studio One 6 V6.0.1 音乐编曲工具 含win/mac版

    亲测有效! Studio One 6 V6.0.1 音乐编曲工具  含win/mac版 记录.生产.混合.掌握和执行所有操作.从工作室到舞台,Studio One6以易用为核心,是您的创意合作伙伴.当 ...

  3. Could not execute query ---> MySql.Data.MySqlClient.MySqlException: You have an error in your SQL sy

    1.出现问题 执行sql查询时出现如题错误,原因是安装mysql-connector-net的版本过高,当前项目在用的mysql版本不符合:关于当前安装的mysql-connector-net版本的查 ...

  4. 修改Element - plus的样式

    把显示再浏览器上的对应css选择器全部写上,并且添加 !important </script> <style lang='scss' scoped> //修改 element ...

  5. nuxt+vant+rem项目构建

    原文链接:https://blog.csdn.net/Young_Gao/article/details/93605428 一.创建项目 1.使用如下命令生成项目 vue init nuxt-comm ...

  6. 【NOIP2013提高组】华容道

    分析 一个比较显然的方式是 设 \(f_{i,j,x,y}\) 表示达到空格所处位置为 \((i,j)\) 且特殊格位置为 \(x,y\) 的状态的最少步数 一次可以交换空格和相邻格,代价为 \(1\ ...

  7. 五十条常用的MySQL语句

    1.查询"001"课程比"002"课程成绩高的所有学生的学号:select a.S# from (select s#,score from SC where C ...

  8. 认识 C 的编译器和编译流程

    GCC 的编译流程 我们写的 C 代码保存在扩展名是 .c 的文件,其实是一个纯文本文件. GCC(C 编译器之一)通过预处理器(Pre-Processing)把头文件展开到hello.i文件中. 编 ...

  9. 剖析flutter_download_manager学习如何做下载管理,暂停和取消

    前言 内容类应用中图片或文件下载,一般应用中应用更新和升级,这些都是经典的下载场景.下载是项目中基础且重要的模块. 从代码逻辑复用性和人力成本考虑,一直想实现一个纯Dart实现的下载库,作为技术储备. ...

  10. 记一次oracle单表改分区表 一波三折

    业务上要把单表还差分区表 ```SQL> @seg gwx.aopen SEG_MB OWNER SEGMENT_NAME SEG_PART_NAME SEGMENT_TYPE SEG_TABL ...