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 已经存在,则直接拿取

原文地址:https://www.cnblogs.com/chihirotan/p/6555280.html