mybatis源码分析二之DefaultSqlSessionFactory

DefaultSqlSessionFactory


  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
         <!-- 上面指定了数据库配置文件, 配置文件里面也是对应的这四个属性 -->
         <property name="driver" value="${driver}"/>
         <property name="url" value="${url}"/>
         <property name="username" value="${username}"/>
         <property name="password" value="${password}"/>

      </dataSource>
    </environment>
  </environments>

    /**
    核心方法,DefaultSqlSessionFactory其他方法都是调用此方法
    **/
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //通过Confuguration对象去获取Mybatis相关配置信息, Environment对象包含了数据源和事务的配置(从上面的配置可以看出)
      final Environment environment = configuration.getEnvironment();
      //通过环境配置获取事务工厂,如果没有配置默认是   new ManagedTransactionFactory();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //通过配置创建一个Executor,Executor是对jdbc中Statement的封装
      final Executor executor = configuration.newExecutor(tx, execType);
      //此处也是写死的,创建一个DefaultSqlSession对象
      return new DefaultSqlSession(configuration, executor);
    } catch (Exception e) {
      //可能已经获取了一个连接,所以此处调用close事务
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }


  private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    if (environment == null || environment.getTransactionFactory() == null) {
      return managedTransactionFactory;
    }
    return environment.getTransactionFactory();
  }

DefaultSqlSession

非mapper接口方式

  1. 代码案例

         @Test
    public void testFindUserMessageIdForSession(){
        //mybatis的配置文件
        String resource = "Configuration.xml";
        //使用类加载器加载mybatis的配置文件(它也加载关联的映射文件)
        InputStream is = UserMessageTest.class.getClassLoader().getResourceAsStream(resource);
        //构建sqlSession的工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
        //使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件)
        //Reader reader = Resources.getResourceAsReader(resource); 
        //构建sqlSession的工厂
        //SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
        //创建能执行映射文件中sql的sqlSession
        SqlSession session = sessionFactory.openSession();
        /**
         * 映射sql的标识字符串,
         * me.gacl.mapping.userMapper是userMapper.xml文件中mapper标签的namespace属性的值,
         * getUser是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL
         */
        String statement = "com.jannal.mybatis.pojo.UserMessageMapper.findUserMessageById";//映射sql的标识字符串
        //执行查询返回一个唯一user对象的sql
        UserMessage user = session.selectOne(statement, 7777);
        System.out.println(user);
    }
  2. 分析session.selectOne

    
            /***
            selectOne调用的额是selectList
            **/
            public <T> T selectOne(String statement, Object parameter) {
            // Popular vote was to return null on 0 results and throw exception on too many.
            List<T> list = this.<T>selectList(statement, parameter);
            if (list.size() == 1) {
              return list.get(0);
            } else if (list.size() > 1) {
              throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
            } else {
              return null;
            }
          }
          public <E> List<E> selectList(String statement, Object parameter) {
            return this.<E>selectList(statement, parameter, RowBounds.DEFAULT);
          }
    
    
          public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
            try {
              /**statement是com.jannal.mybatis.pojo.UserMessageMapper.findUserMessageById        在Configuration中通过id为com.jannal.mybatis.pojo.UserMessageMapper.findUserMessageById获取MappedStatement
              **/
              MappedStatement ms = configuration.getMappedStatement(statement);
              //调用Executor接口的query执行
              List<E> result = executor.<E>query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
              return result;
            } catch (Exception e) {
              throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
            } finally {
              ErrorContext.instance().reset();
            }
          }

  3. CachingExecutor

         public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
            Cache cache = ms.getCache();
            if (cache != null) {
              flushCacheIfRequired(ms);
              if (ms.isUseCache() && resultHandler == null) { 
                ensureNoOutParams(ms, key, parameterObject, boundSql);
                cache.getReadWriteLock().readLock().lock();
                try {
                  @SuppressWarnings("unchecked")
                  List<E> cachedList = dirty ? null : (List<E>) cache.getObject(key);
                  if (cachedList != null) {
                    return cachedList;
                  } else {
                    List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                    tcm.putObject(cache, key, list);
                    return list;
                  }
                } finally {
                  cache.getReadWriteLock().readLock().unlock();
                }
              }
            }
            //委托类是SimpleExecutor
            return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          }
    /**
    SimpleExecutor中的<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    */
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;
        try {
          Configuration configuration = ms.getConfiguration();
          StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);
          stmt = prepareStatement(handler, ms.getStatementLog());
          return handler.<E>query(stmt, resultHandler);
        } finally {
          closeStatement(stmt);
        }
      }
    

mapper接口方式

  1. 案例代码

        @Test
        public void testFindUserMessageIdForMapper(){
            String resource = "Configuration.xml";
            InputStream is = UserMessageTest.class.getClassLoader().getResourceAsStream(resource);
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession session = sessionFactory.openSession();
            UserMessageMapper userMessageMapper = session.getMapper(UserMessageMapper.class);
            UserMessage userMessage = userMessageMapper.findUserMessageById(7777L);
            System.out.println(userMessage);
        }
  2. 源码分析

         /**session.getMapper(UserMessageMapper.class);是调用DefaultSqlSession中的如下方法。
        DefaultSqlSession从Configuration中获取mapper
         **/
         public <T> T getMapper(Class<T> type) {
            return configuration.<T>getMapper(type, this);
          }
    
          /**
          此方法是Configuration中个getMapper(),可以看出Configuration委托MapperRegistry
         **/
          public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
            return mapperRegistry.getMapper(type, sqlSession);
          } 
    
         /**
         此方法是MapperRegistry下的getMapper()方法
         ***/ 
         public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
            if (!knownMappers.contains(type))
              throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
            try {
            //MapperProxy动态代理Mapper接口(每个MapperProxy对应一个mapper接口)
              return MapperProxy.newMapperProxy(type, sqlSession);
            } catch (Exception e) {
              throw new BindingException("Error getting mapper instance. Cause: " + e, e);
            }
          }       

  3. MapperProxy

        /**
        1. UserMessageMapper userMessageMapper = session.getMapper(UserMessageMapper.class);
         UserMessage userMessage = userMessageMapper.findUserMessageById(7777L);
         userMessageMapper此时是MapperProxy。此时通过MapperProxy去调用findUserMessageById
        2. 
        **/
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //找到method对应的接口
            final Class<?> declaringInterface = findDeclaringInterface(proxy, method);
            //委托给MapperMethod去处理sql的执行
            final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);
            final Object result = mapperMethod.execute(args);
            if (result == null && method.getReturnType().isPrimitive() && !method.getReturnType().equals(Void.TYPE)) {
              throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
            }
            return result;
          }
    
    
         /**
         以下是MapperMethod方法,可以看到MapperMethod采用命令模式
         **/
          public Object execute(Object[] args) {
            Object result = null;
            if (SqlCommandType.INSERT == type) {
              Object param = getParam(args);
              result = sqlSession.insert(commandName, param);
            } else if (SqlCommandType.UPDATE == type) {
              Object param = getParam(args);
              result = sqlSession.update(commandName, param);
            } else if (SqlCommandType.DELETE == type) {
              Object param = getParam(args);
              result = sqlSession.delete(commandName, param);
            } else if (SqlCommandType.SELECT == type) {
              if (returnsVoid && resultHandlerIndex != null) {
                executeWithResultHandler(args);
              } else if (returnsMany) {
                result = executeForMany(args);
              } else if (returnsMap) {
                result = executeForMap(args);
              } else {
                Object param = getParam(args);
                //可以看到调用的还是sqlSession.selectOne,即调用非Mapper接口处理的方式
                result = sqlSession.selectOne(commandName, param);
              }
            } else {
              throw new BindingException("Unknown execution method for: " + commandName);
            }
            return result;
          }

猜你喜欢

转载自blog.csdn.net/usagoole/article/details/80639261