上篇 详细分析了org.mybatis.spring.mapper.MapperScannerConfigurer 和 org.mybatis.spring.SqlSessionFactoryBean的作用,可以直接看最后的总结

MapperFactoryBean是mapper接口的入口,它包含了sqlSessionFactory的封装SqlSessionTemplate,而sqlSessionFactory又包含了mapper xml的组装Configuration对象

从SqlSessionTemplate的

public <T> T getMapper(Class<T> type) {    return this.getConfiguration().getMapper(type, this);}

开始,进入Configuration的getMapper(type,sqlsession)

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {    return this.mapperRegistry.getMapper(type, sqlSession);}

进入MapperRegistry

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {    MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);    if(mapperProxyFactory == null) {        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");    } else {        try {            return mapperProxyFactory.newInstance(sqlSession);        } catch (Exception var5) {            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);        }    }}

由MapperProxyFactory生成代理MapperProxy

protected T newInstance(MapperProxy<T> mapperProxy) {    return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);}

public T newInstance(SqlSession sqlSession) {    MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);    return this.newInstance(mapperProxy);}

所以最终的调用会进入MapperProxy,接下来几步在 mybatis缓存 中有介绍,会调用sqlSession(实际是SqlSessionTemplate)中的方法,看构造方法:

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {Assert.notNull(sqlSessionFactory, "Property \'sqlSessionFactory\' is required");Assert.notNull(executorType, "Property \'executorType\' is required");this.sqlSessionFactory = sqlSessionFactory;this.executorType = executorType;this.exceptionTranslator = exceptionTranslator;this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());}

会对SqlSessionFactory生成代理,实际调用这个代理的方法

public <T> T selectOne(String statement) {    return this.sqlSessionProxy.selectOne(statement);}

1. 进入SqlSessionTemplate.SqlSessionInterceptor

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);   ......    Object t = method.invoke(sqlSession, args);    ......}

看SqlSessionUtils.getSqlSession方法:

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {Assert.notNull(sessionFactory, "No SqlSessionFactory specified");Assert.notNull(executorType, "No ExecutorType specified");SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);if(holder != null && holder.isSynchronizedWithTransaction()) {if(holder.getExecutorType() != executorType) {throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");} else {holder.requested();if(logger.isDebugEnabled()) {logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");}return holder.getSqlSession();}} else {//进入这里呀呀呀if(logger.isDebugEnabled()) {logger.debug("Creating a new SqlSession");}
       //step 1.1SqlSession session = sessionFactory.openSession(executorType);if(TransactionSynchronizationManager.isSynchronizationActive()) {Environment environment = sessionFactory.getConfiguration().getEnvironment();if(environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {if(logger.isDebugEnabled()) {logger.debug("Registering transaction synchronization for SqlSession [" + session + "]");}//step 1.2holder = new SqlSessionHolder(session, executorType, exceptionTranslator);TransactionSynchronizationManager.bindResource(sessionFactory, holder);TransactionSynchronizationManager.registerSynchronization(new SqlSessionUtils.SqlSessionSynchronization(holder, sessionFactory));holder.setSynchronizedWithTransaction(true);holder.requested();} else {if(TransactionSynchronizationManager.getResource(environment.getDataSource()) != null) {throw new TransientDataAccessResourceException("SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");}if(logger.isDebugEnabled()) {logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional");}}} else if(logger.isDebugEnabled()) {logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");}return session;}}

1.1 进入DefaultSqlSessionFactory openSession方法:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;DefaultSqlSession var8;try {Environment e = this.configuration.getEnvironment();//springManagedTransactionFactoryTransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(e);tx = transactionFactory.newTransaction(e.getDataSource(), level, autoCommit);Executor executor = this.configuration.newExecutor(tx, execType, autoCommit);var8 = new DefaultSqlSession(this.configuration, executor);} catch (Exception var12) {this.closeTransaction(tx);throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);} finally {ErrorContext.instance().reset();}return var8;}

进入SpringManagedTransactionFactory的

newTransaction(e.getDataSource(), level, autoCommit);

返回

return new SpringManagedTransaction(dataSource);

这个SpringManagedTransaction比较特别,因为

private void openConnection() throws SQLException {    this.connection = DataSourceUtils.getConnection(this.dataSource);    this.autoCommit = this.connection.getAutoCommit();    this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);    if(this.logger.isDebugEnabled()) {        this.logger.debug("JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional?" ":" not ") + "be managed by Spring");    }}

因为它的连接来自DataSourceUtils

public static Connection doGetConnection(DataSource dataSource) throws SQLException {Assert.notNull(dataSource, "No DataSource specified");ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);if(conHolder == null || !conHolder.hasConnection() && !conHolder.isSynchronizedWithTransaction()) {logger.debug("Fetching JDBC Connection from DataSource");Connection con = dataSource.getConnection();if(TransactionSynchronizationManager.isSynchronizationActive()) {logger.debug("Registering transaction synchronization for JDBC Connection");ConnectionHolder holderToUse = conHolder;if(conHolder == null) {holderToUse = new ConnectionHolder(con);} else {conHolder.setConnection(con);}holderToUse.requested();TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource));holderToUse.setSynchronizedWithTransaction(true);if(holderToUse != conHolder) {TransactionSynchronizationManager.bindResource(dataSource, holderToUse);}}return con;} else {conHolder.requested();if(!conHolder.hasConnection()) {logger.debug("Fetching resumed JDBC Connection from DataSource");conHolder.setConnection(dataSource.getConnection());}return conHolder.getConnection();}}

这一步就和 spring--事务原理 中分析的对接了!!!connection连接对象来自当前线程绑定的ConnectionHolder中的connection对象

最终 DefaultSqlSession-》Executor-》Transaction-》当前线程绑定的ConnectionHolder中的connection对象

1.2 构建SqlSessionHolder-》DefaultSqlSession,并绑定到当前线程<sessionFactory,session holder>

2. DefaultSqlSession的执行见  mybatis缓存

转载于:https://www.cnblogs.com/yhzh/p/5588390.html

mybatis--MapperProxy事务相关推荐

  1. spring boot配置mybatis和事务管理

    spring boot配置mybatis和事务管理 一.spring boot与mybatis的配置 1.首先,spring boot 配置mybatis需要的全部依赖如下: <!-- Spri ...

  2. Spring MVC+MyBatis中Spring没有接管Mybatis的事务

    今天把框架整合完毕,测试时发现,无论使不使用aop还是@Transactional,service层中的对应新增等方法都会保存成功.跟踪代码发现在org.mybatis.spring.SqlSessi ...

  3. mybatis plus 事务管理器_Mybatis中的事务

    Mybatis中的事务 数据库中的事务可以保证在连续执行的多条写操作(增删改)时,这多条操作要么成功,要么全部失败,以保证数据和逻辑的完整及严谨 在使用mybatis时,无需考虑事务如何创建,如何提交 ...

  4. 测试Mybatis时事务自动回滚,无法完成增删改

    场景 单独使用myBatis进行测试时,进行增删改查,进行查询时正常显示,但是进行插入.修改.删除时数据库中总是没法修改,查看控制台输出: 原因 默认情况下,事务不是自动提交 查看Mybatis的op ...

  5. SpringBoot(配置druid数据源、配置MyBatis、事务控制、druid 监控)

    SpringBoot 得到最终效果是一个简化到极致的 WEB 开发,但是只要牵扯到 WEB 开发,就绝对不可能缺少 数据层操作,所有的开发都一定秉持着 MVC 设计模式的原则,MVC 里面业务层不可少 ...

  6. myBatis之事务管理

    1. myBatis单独使用时,使用SqlSession来处理事务: Java代码   public class MyBatisTxTest { private static SqlSessionFa ...

  7. mybatis plus 事务管理器_SpringBoot第七篇:springboot开启声明式事务

    springboot开启事务很简单,只需要一个注解@Transactional 就可以了.因为在springboot中已经默认对jpa.jdbc.mybatis开启了事事务,引入它们依赖的时候,事物就 ...

  8. mybatis plus 事务管理器_学习MyBatis 框架

    1. 框架是什么? a 框架就就是写好的功能架构 一些重复的代码的深度的封装 b 框架也是一个半成品 调用同时 也需要告诉框架一些信息 c一般以配置文件方式告知框架 多数会使用Xml作为框架的配置文件 ...

  9. spring+mybatis 一个事务中两次查询结果不一样的问题

    最近搞了一波事情,把一个接口给重构了一番,感觉还不错,同时也遇到了一些问题,这个就是其中一个. 因为重构,我在这个接口上面加了一个事务,然后就发现之前的代码跑出来的结果就不一样了,两次一模一样的查询, ...

  10. mybatis plus 事务管理器_最全MyBatis核心配置文件总结,可以作为工具先收藏了

    作者:双子孤狼 来源:blog.csdn.net/zwx900102/article/details/108492263 前言 今天这咱主要介绍一下MyBatis的全局配置文件的使用 configur ...

最新文章

  1. 这个寒冬,如何让我们的身价翻倍?
  2. HDU 6035 Colorful Tree(补集思想+树形DP)
  3. hive与hbase整合方式和优劣
  4. php字符串转int,php怎样将字符串转为int类型
  5. Python —— 字符串常用操作
  6. 三大统计相关系数:Pearson、Spearman秩相关系数、kendall等级相关系数
  7. Docker系列(二)Docker安装与启动
  8. Maven使用yuicompressor-maven-plugin打包压缩css、js文件
  9. java jframe 图标_java怎么修改jframe图标?
  10. 嵌入式软件架构的设计
  11. 【新书推荐】【2021】基于多源信息融合的航天器自主导航技术
  12. Stata:快速转换工作路径
  13. android自带网页提供,Android调用系统自带浏览器打开网页的实现方法
  14. MySqL数据库监听命令_Mysql数据库监听binlog
  15. SAS首席科学家:如何选择机器学习算法?
  16. Ping IPv6在线测试检测 testipv6 加速镜像
  17. asd激光粒度仪测试原理是什么解答
  18. 微信发照片怎么在服务器上删除,我们发现微信发送原图,确实会暴露位置信息!但你可以这么解决...
  19. git切换master项目,新建分支new branch
  20. 我的世界怎么在服务器中显示键位,我的世界神奇宝贝mod怎么玩 基本键位介绍...

热门文章

  1. maven 配置文件 settings.xml
  2. 移植开源QT软件-SameGame
  3. 人脸检测的harr检测函数
  4. axios post传递对象_axios的post传参时,将参数转为form表单格式
  5. 关于SVN 目录结构
  6. js移除字符串的中文/空格
  7. 【Solr】- Tomcat部署
  8. Python自动化开发学习22-Django下(Form)
  9. Linux(CentOS)同步时间
  10. Linus Torvalds:回顾Linux20年