mybatis 核心逻辑处理篇

mybatis 核心逻辑处理篇:

通过解析返回的 Configuration 对象,

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
【new DefaultSqlSessionFactory(config);】

核心我们从 DefaultSqlSessionFactory.class 源码说起。 通过创建工厂获取到 SqlSession 。然而创建 SqlSession 的因素需要 DataSource 和 TransactionFactory 二个。通过数据源及事务工厂我们可以得到 Transaction 对象。 (Transaction 对象可以获取数据库连接、可以提交事务、可以回滚事务、关闭连接、可以获取到事务超时)。得到 Transaction 事务可以使用 Configuration 创建执行器 Executor 。 而 SqlSession 就是封装 Executor 的对象来操作数据库。


	private final Configuration configuration;

	public SqlSession openSession() {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);//无参数
    }

	private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
            // 获取环境  (事务工厂、数据源)
            final Environment environment = configuration.getEnvironment();
            // 获取事务工厂  (JdbcTransactionFactory / 默认ManagedTransactionFactory / SpringManagedTransactionFactory)
            final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
            // 通过工厂创建事务  (JdbcTransaction / ManagedTransaction / SpringManagedTransaction)
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            // 通过事务和 ExecutorType 创建执行器  (SimpleExecutor / CachingExecutor / BatchExecutor)
            final Executor executor = configuration.newExecutor(tx, execType);// 通过拦截器处理 执行器(是否创建代理)
            // 通过执行器创建 SqlSession
            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();
        }
    }

根据代码可以发现,可以通过 Environment 对象获取到事务工厂及数据源 (TransactionFactory \ DataSource) , 然后通过事务工厂可以创建事务对象 (Transaction)

Transaction transaction = transactionFactory.newTransaction(dataSource, null, false);

例如:

JdbcTransactionFactory 创建 => JdbcTransaction
ManagedTransactionFactory 创建 => ManagedTransaction

到这说下 DataSource 跟 TransactionFactory 的创建 ,上一章解析篇没分析mybatis-config.xml 中的 environments 节点解析。。 在这简单说下解析逻辑

 <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>

解析对应的节点, 获取属性type 然后找到对应的class 初始化。在通过封装成 Environment 对象储存到 Configuration 配置中心

	//解析<environments> 节点
    private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
            if (environment == null) {
                environment = context.getStringAttribute("default");
            }
            //获取子节点 <environment id="development">
            for (XNode child : context.getChildren()) {
                String id = child.getStringAttribute("id");
                if (isSpecifiedEnvironment(id)) {
                    // TransactionFactory
                    TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
                    // DataSourceFactory
                    DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
                    // DataSource
                    DataSource dataSource = dsFactory.getDataSource();
                    // Environment
                    Environment.Builder environmentBuilder = new Environment.Builder(id)
                            .transactionFactory(txFactory)
                            .dataSource(dataSource);
                    configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }
    }

	// 解析 <transactionManager type="JDBC"/>
    private TransactionFactory transactionManagerElement(XNode context) throws Exception {
        if (context != null) {
            String type = context.getStringAttribute("type");
            Properties props = context.getChildrenAsProperties();
            // 如: type 为 JDBC 就会创建 JdbcTransactionFactory 
            TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
            factory.setProperties(props);
            return factory;
        }
        throw new BuilderException("Environment declaration requires a TransactionFactory.");
    }

	// 解析 <dataSource type="POOLED"> 
	private DataSourceFactory dataSourceElement(XNode context) throws Exception {
        if (context != null) {
            String type = context.getStringAttribute("type");
            Properties props = context.getChildrenAsProperties();
            DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
            factory.setProperties(props);
            return factory;
        }
        throw new BuilderException("Environment declaration requires a DataSourceFactory.");
    }

其中 resolveClass() 方法作用就是通过name找到已经注册的class 然后实例化.
在这里插入图片描述
这下我们就可以知道通过配置属性值找个对应的DataSource 及 TransactionFactory 。
然后可以看到通过 DataSource 创建了 Transaction 事务对象,在通过事务对象(Transaction)和执行器类型(ExecutorType)创建 对应的执行器(Executor)

final Executor executor = configuration.newExecutor(tx, execType); // CachingExecutor
Executor 讲下: 比较重要的二个方法 update() 与 query().
可以通过 mybatis 中 Interceptor 接口来进行拦截进行sql 语句的修改,例如分页功能

根据执行器(Executor)创建 SqlSession

SqlSession sqlSession = new DefaultSqlSession(configuration, executor, false);
List entitys = sqlSession.selectList(“findAll”);

DefaultSqlSession#selectList() 核心方法
逻辑:根据 id 标识找到对应的标签封装对象 MappedStatement , 在通过 执行器 Executor 执行对应的sql 。

	public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        try {
            //根据id 查询对应的映射语句对象
            MappedStatement ms = configuration.getMappedStatement(statement);
            return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }

执行器 Executor => BaseExecutor 中四个抽象方法
1、SimpleExecutor 简单执行器(默认)
2、BatchExecutor 分批执行器
3、ReuseExecutor 重用执行器
4、CachingExecutor 缓存执行器(装饰模式)
逻辑:

	public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {//
        //通过MappedStatement 获取sql语句
        BoundSql boundSql = ms.getBoundSql(parameter);
        //创建CacheKey
        CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);//
        return query(ms, parameter, rowBounds, resultHandler, key, boundSql);//
    }
	
	// rowBounds
	public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {//
        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
        if (closed) {
            throw new ExecutorException("Executor was closed.");
        }
        if (queryStack == 0 && ms.isFlushCacheRequired()) {
            clearLocalCache();
        }
        List<E> list;
        try {
            queryStack++; //查询次数+1

            //先从缓存读取, 如若找到就不查询数据库
            list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
            if (list != null) {
            	//处理本地缓存参数(一般不做处理)
                handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);//处理本地缓存输出参数
            } else {
            	//	如果缓存为空就查询数据库
                list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
            }
        } finally {
            queryStack--;
        }
        if (queryStack == 0) {
            for (DeferredLoad deferredLoad : deferredLoads) {
                deferredLoad.load();
            }
            // issue #601
            deferredLoads.clear();
            if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                // issue #482
                clearLocalCache();
            }
        }
        return list;
    }

	/**
     * 查询数据库
     */
    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;
        localCache.putObject(key, EXECUTION_PLACEHOLDER); //先储存为null
        try {
            //doQuery 抽象方法
            list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            localCache.removeObject(key);
        }
        localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {  //默认 PREPARED
            localOutputParameterCache.putObject(key, parameter);
        }
        return list;
    }       

抽象方法

	//修改
	protected abstract int doUpdate(MappedStatement ms, Object parameter)
            throws SQLException;

    protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
            throws SQLException;

	// 查询
    protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
            throws SQLException;

    protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
            throws SQLException;

核心逻辑先分析到这, 下章会继续介绍 缓存篇(PerpetualCache)与事务篇

猜你喜欢

转载自blog.csdn.net/baidu_36327010/article/details/89323972
今日推荐