• myBatis 切换数据源(spring事务)理解


    1. mybatis (SqlSessionTemplate)的动态代理

      a) sqlSession的结构

      

      b)SqlSession 结构

    public class SqlSessionTemplate implements SqlSession {
      //代理对象 ------1
      private final SqlSession sqlSessionProxy;
      /**
       *//构造方法 --------2
       */
      public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
          PersistenceExceptionTranslator exceptionTranslator) {
        //利用jdk的动态代理,生成sqlSessionProxy的代理对象--------3
        this.sqlSessionProxy = (SqlSession) newProxyInstance(
            SqlSessionFactory.class.getClassLoader(),
            new Class[] { SqlSession.class },
            new SqlSessionInterceptor());
      }
    
      /**
       */
      @Override
      public <T> T selectOne(String statement) {
        //代用代理对象的目标方法,触发代理对象的产生---------4
        return this.sqlSessionProxy.<T> selectOne(statement);
      }
    
      /**
       */
      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 {
            //代理对象执行,实际上执行的是sqlSession的目标方法,proxy没有执行--------5
            Object result = method.invoke(sqlSession, args);
            if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
              // 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);
            }
          }
        }
      }
    
    } 

    2.没有事务:切换数据源(成功切换数据源)

      a)代理对象执行目标时,切换数据源时 (栈结构)

     

      b) 在DataSourceUtils 中,判断conHolder是否为空,

    3.存在事务:切换数据源(不会切换数据源)

      a)  在执行目标方式时,被spring拦截,检查是否存在事务,(存在事务,调用doBegin方法,为事务准备链接conncetion)

     

      b) 代理对象sqlSessionTemple 执行目标方法中,在DataSourceUtils 中判断connection 已经存在,则直接拿取

  • 相关阅读:
    搜广推04-信息检索任务&数据集&LeadBoard&评价指标
    搜广推&NLP03-顶会track记录
    搜广推02-DeepMatch 模型总结[SIGIR2019 tutorial]
    搜广推01-信息检索领域大佬总结
    计算机基础01-终端命令行、VIM、git、CICD
    【python】彼岸图网4K壁纸批量爬虫共1.48G(多线程/多进程)
    【python】不到500行代码实现flappybird小游戏
    解决pyinstaller打包程序太大的问题
    解决pipenv install报错FileNotFoundError: [Errno 2] No such file or directory: ‘d:\miniconda3\Lib\venv
    【python】如何将matplotlib的标题置于图片下方
  • 原文地址:https://www.cnblogs.com/chihirotan/p/6555280.html
Copyright © 2020-2023  润新知