Mybatis 源码分析一 SqlSessionFactory

Mybatis 源码分析一 SqlSessionFactory

我们先来看看Mybatis官方对于Mybatis的简介
		MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
		MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old JavaObjects,普通老式 Java 对象)为数据库中的记录。
从这段可以看出Mybatis封装了JDBC并使用XML配置来让我们操作数据库,那么他的执行流程是怎样的呢,
我们先从一个简单的例子来分析他的执行流程
	@Test
	public void sqlSessionFactoryByXML() throws IOException {
     
		// 路径
		String resource = "mybatis-test.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);		
		//SqlSessionFactoryBuilder.build方法会自动关闭流
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"test");
		try (SqlSession session = sqlSessionFactory.openSession();) {
     
			TbItemMapper mapper = session.getMapper(TbItemMapper.class);
			TbUserMapper usermapper = session.getMapper(TbUserMapper.class);
			TbUser user = usermapper.selectByPrimaryKey((long) 7);
			TbItem item = mapper.selectByPrimaryKey((long) 562379);
			System.out.println(user);
			System.out.println(item);
		}

	}

重要的与数据库交互对象SqlSession

	SqlSession是Mybatis提供给用户与数据库交互的重要对象,我们可以调用SqlSession的getMapper方法来取得
	Mapper代理类,而SqlSession由SqlSessionFactory构建,SqlSessionFactory由SqlSessionFactoryBuilder构建而来
	我们先看SqlSessionFactoryBuilder以及SqlSessionFactory源码来分析SqlSession是怎么样创建的

SqlSessionFactoryBuilder的主要方法

	/**
	 * 	根据字节流构建SqlSessionFactroy
	 * */
  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
     
    try {
     
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      //调用重载的方法build(Configuration config)
      return build(parser.parse());
    } catch (Exception e) {
     
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
     
      ErrorContext.instance().reset();
      try {
     
        inputStream.close(); //流会关闭
      } catch (IOException e) {
     
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
  	/**
	 * 	根据字节流构建SqlSessionFactroy
	 * */
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
     
    try {
     
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
     
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
     
      ErrorContext.instance().reset();
      try {
     
        reader.close();
      } catch (IOException e) {
     
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
 /**
  * new 一个DefaultSqlSessionFactory
 * @param config mybatis核心配置文件转换成的类
 * @return
 */
  public SqlSessionFactory build(Configuration config) {
     
    return new DefaultSqlSessionFactory(config);
  }

SqlSessionFactoryBuilder读取了核心配置文件一般名字是Mybatis.xml 用XMLConfigBuilder 类来构建了Configuration ,Configuration是一个重要的对象,它封装了Mybatis.xml的所以配置文件,接着直接
new 了一个DefaultSqlSessionFactory 并返回

DefaultSqlSessionFactory

	public SqlSession openSession() {
     
		return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
	}
	public SqlSession openSession(Connection connection) {
     
		return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
	}
		private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
			boolean autoCommit) {
     
		Transaction tx = null;
		try {
     
			//取得核心配置文件所映射的Environment类
			final Environment environment = configuration.getEnvironment();
			//根据环境的配置如取得事务工厂
			final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
			tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
			//configuration 取得执行器 是什么类型的执行器则根据execType来判断,这里注意cacheExecutor只是一个装饰器,如果需要二级缓存,就会装饰相应的Executor
			//核心配置文件中的插件也将改变Executor的行为 : Executor的分析看executor包下
			final Executor executor = configuration.newExecutor(tx, execType);
			return new DefaultSqlSession(configuration, executor, autoCommit);
		} catch (Exception e) {
     
			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 SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
     
		try {
     
			boolean autoCommit;
			try {
     
				autoCommit = connection.getAutoCommit();
			} catch (SQLException e) {
     
				// Failover to true, as most poor drivers
				// or databases won't support transactions
				autoCommit = true;
			}
			final Environment environment = configuration.getEnvironment();
			final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
			final Transaction tx = transactionFactory.newTransaction(connection);
			final Executor executor = configuration.newExecutor(tx, execType);
			return new DefaultSqlSession(configuration, executor, autoCommit);
		} catch (Exception e) {
     
			throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
		} finally {
     
			ErrorContext.instance().reset();
		}
	}
	/**
	 * 	如果 环境节点配置了事务类型则跟据配置返回TransactionFactory,如果没有配置放回ManagedTransactionFactory
	 * */
	private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
     
		if (environment == null || environment.getTransactionFactory() == null) {
     
			return new ManagedTransactionFactory();
		}
		return environment.getTransactionFactory();
	}

DefaultSqlSessionFactory 的两个核心的取SqlSession 的方法openSessionFromDataSource,openSessionFromConnection。两者的逻辑大致相似,都new 了一个DefaultSqlSession并把Configuration,Executor,是否自动commit等属性注入到了DefaultSqlSession,不同的是openSessionFromDataSource接受TransactionIsolationLevel level boolean autoCommit,
根据这些配置构建事务,而openSessionFromConnection 接受一个Connection来构建事务,其实原理是一样的,事务封装了Connection,事务工厂的newTransaction方法根据接收的TransactionIsolationLevel ,autoCommit构建Connection并注入到事务中返回

总结
以上大致就是取得一个SqlSession的流程,SqlSessionFactoryBuilder通过XMLConfigBuilder得到Configuration注入到DefaultSqlSessionFactory中并返回DefaultSqlSessionFactory实例,DefaultSqlSessionFactory根据Configuration生成不同的执行器Executor,事务Transaction注入到DefaultSqlSession中并返回该实例,这样我们就得到了一个SqlSession。
对于Executor,Transaction我们会在以后的章节中分析
[下一篇]: Mybais 源码分析二 SqlSession

你可能感兴趣的:(Mybatis,Mybatis,Mybatis源码分析)