MyBatis-Spring中MyBatis概要流程

一、初始化SqlSessionFactory

核心流程

核心使用到了SqlSessionFactoryBean的afterPropertiesSet、getObject方法

afterPropertiesSet:用于初始化并封装数据

getObject:用于注入DefaultSqlSessionFactory对象到容器中

详情逻辑

一、在将SqlSessionFactoryBean放在IOC容器过程中,由于SqlSessionFactoryBean实现了InitializingBean#afterPropertiesSet方法
afterPropertiesSet会做以下几件事
1. 将配置信息封装到Configuration对象中
2. 读取并解析各个配置的xml文件并封装到Configuration的Map<String, MappedStatement> mappedStatements对象中,key是xml的名称空间+各个标签id,value是标签的内容
3. 同时会加载各个名称空间得到Class对象,构建相应的代理工厂对象MapperProxyFactory到MapperRegistry的Map<Class<?>, MapperProxyFactory<?>> knownMappers中,方便创建代理对象使用
将封装好数据的Configuration对象作为属性放在创建的DefaultSqlSessionFactory对象中,这样就构建了DefaultSqlSessionFactory对象

二、SqlSessionFactoryBean其实现了FactoryBean#getObject方法,getObject方法会将上边的DefaultSqlSessionFactory对象注入到IOC容器中

相应配置

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!--映射配置文件位置-->
    <property name="mapperLocations" value="classpath:/mapper/*.xml"/>

    <!--其他配置-->
    <property name="configuration">
        <bean class="org.apache.ibatis.session.Configuration">
            <!--开启列名转驼峰映射配置-->
            <property name="mapUnderscoreToCamelCase" value="true"/>
            <!--日志输出到控制台-->
            <property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
        </bean>
    </property>
</bean>

二、创建接口的代理对象并放在IOC容器中

核心流程

为每个接口创建间桥梁sqlSessionTemplate对象

将创建的映射器接口代理对象放在IOC容器中

详情逻辑

MapperFactoryBean继承了SqlSessionDaoSupport,会为每个接口创建sqlSessionTemplate对象,其作为一个中间桥梁,当sqlSessionTemplate执行方法时会委托给其内部的sqlSessionProxy代理对象执行

sqlSessionProxy代理对象执行相应的方法时会走增强逻辑SqlSessionInteceptior#invoke方法,invoke方法才会真正创建DefaultSqlSession对象,

创建DefaultSqlSession对象有以下重要步骤

  1. 会将DefaultSqlSession作为value,DefaultSqlSessionFactory对象作为key放在线程的局部变量TheadLocal
  2. 会与Spring的事务进行挂钩,创建Executor对象(比如SimpleExecutor),并将Spring事务放在BaseExecutor,为了后续在Executor执行方法时从Spring事务中获取数据库连接(spring事务本质上也是通过ThreadLocal对象拿的数据库连接,数据源作为key,数据库连接对象作为value)
    相关方法:
    org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke
    org.mybatis.spring.SqlSessionUtils#getSqlSession()
    org.apache.ibatis.executor.SimpleExecutor#prepareStatement
    org.mybatis.spring.transaction.SpringManagedTransaction#openConnection

通过org.mybatis.spring.mapper.MapperFactoryBean#getObject方法将生成的映射器接口代理对象放在IOC容器中

<bean id="tbRoleInfoMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.abucloud.mapper.TbRoleInfoMapper"/>
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<bean id="userInfoMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.abucloud.mapper.UserInfoMapper"/>
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

补充:MapperFactoryBean有两个重要作用,一是将接口的代理对象注入到容器中,二是当没有指定mapperLocations配置文件时,会自动以接口的全限定名去相同的类路径下找匹配的xml文件

三:代理对象执行目标方法

核心流程

通过MapperProxy#invoke作为入口,SqlSesionTemplate中间桥梁委托给sqlSessionProxy执行,再通过SqlSessionInterceptor#invoke方法创建真正的DefaultSqlSession对象执行crud

详情逻辑

1. 代理对象执行目标方法,就会执行MapperProxy#invoke方法,会构建MapperMethod,解析拿到映射器接口及相应的mapperStatement对象
2. 通过mapperMethod找到执行哪个操作(crud),接着继续委托给sqlSessionTemplate(是在创建MapperProxy对象塞进去的)执行
3. sqlSessionTemplate会继续委托给sqlSessionProxy对象执行,其是代理对象,执行操作会触发增强逻辑SqlSessionInterceptor执行
4. SqlSessionInterceptor内部会创建DefaultSqlSession对象,反射执行内部相应的方法
5. DefaultSqlSession会继续委托给相应的Exexutor(比如是simpleExecutor)
6. Exexutor会从数据源中拿数据库连接对象,通过ParameterHandler进行参数解析(Java数据->sql数据)
7. 最终通过PreparedStatementHandler执行jdbc操作,拿到返回结果集通过ResultSetHandler处理解析结果集(sql数据->Java数据)

其他

1.在同一个spring事务中,自始至终使用的都是同一个DefalutSqlSession对象,原因是创建DefalutSqlSession时会将其绑定到线程的局部变量中,key是DefalutSqlSessionFactory,value是DefalutSqlSession对象
2.真正关闭sqlSession对象在SqlSessionTemplate的beforeCompletion/afterCompletion,而这两个方法beforeCompletion/afterCompletion触发的时机是spring事务TransationAspectSupport执行结束后会触发

3.TransactionSynchronizationManager#isSynchronizationActive的理解

image

posted @ 2024-11-03 22:12  永无八哥  阅读(5)  评论(0编辑  收藏  举报