Mybatis架構設計及源碼分析-SqlSessionFactory 原

Mybatis作爲一個ORM框架目前在企業級開發中使用之非常多,說到ORM框架Mybatis其實並不算一個完整的ORM框架這個在Mybatis文檔中也有說明,確實Mybtais只是實現了訪問數據庫的過程我們還是需要自己去寫sql語句,當然正是這種妙處使得Mybatis的靈活性非常大。SqlSessionFactory是mybatis中的重要組件,下面我們還是回到編程式使用mybatis的例子上面來,上一篇文章已經分析了Configuration對象的初始化過程了,初始化後將會根據Configuration對象生成SqlSessionFactory組件,下面將具體分析下過程。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="false"/>
    </settings>

    <typeAliases>
        <typeAlias type="com.github.wenbo2018.dao.UserDao" alias="User"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/> <!--事務管理類型-->
            <dataSource type="POOLED">
                <property name="username" value="test"/>
                <property name="password" value="123456"/>
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.1.150/ssh_study"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="userMapper.xml"/>
    </mappers>

</configuration>
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession session = sqlSessionFactory.openSession();
try {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
  session.close();
}
public SqlSessionFactory build(Configuration config) {
  return new DefaultSqlSessionFactory(config);
}

這面代碼生成了SqlSessionFactory,可以看出默認的實現是DefaultSqlSessionFactory,SqlSessionFactory接口比較簡單主要是一些打開並獲取SqlSession的方法。默認使用下面方法:

 SqlSession sqlSession = sqlSessionFactory.openSession();

最終調用的方法是:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      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();
    }
  }

代碼中首先獲取到Environment信息,接口從環境Environment獲取到事務工廠TransactionFactory,默認Environment沒有事務工廠的會使用ManagedTransactionFactory,一般情況下直接使用mybatis會使用JDBC事務(暫時不考慮與Spring集成)。

tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

這句代碼生成了通過事務工廠獲取到了一個事務這裏使用的是JDBC事務,

final Executor executor = configuration.newExecutor(tx, execType);這句代碼是生成一個Executor,Executor是mybatis的重要組件之一,是執行sql的重要部分,後續詳細分析,我們看看他是如何生成。

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }


executorType從前面可以看到默認使用的是ExecutorType.SIMPLE模式。故這裏執行的是executor = new SimpleExecutor(this, transaction);這句代碼,我們也可以通過以下方法來執行生成具體的Executor:

SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

各種executor的區別這裏暫時不分析,後續詳細分析。如果cacheEnabled開關被打開的話會使用CachingExecutor,默認情況下cacheEnabled=false,故這裏使用的是SimpleExecutor。

executor = (Executor) interceptorChain.pluginAll(executor);

這句代碼是將executor注入的攔截器鏈中,之前分析過我們可以自己編寫插件這樣執行sql語句時會執行攔截調用。暫時不具體分析調用過程,初步看代代碼這裏使用了一個裝飾器模式。

final Executor executor = configuration.newExecutor(tx, execType);

這句代碼後得到的是SimpleExecutor,接着構造sqlsession,使用的是DefaultSqlSession

return new DefaultSqlSession(configuration, executor, autoCommit);

autoCommit這裏是false表明默認會數據庫會關閉自動提交和開啓事務,屬於一次性事務要麼成功要麼失敗,當前所有的操作都爲一個事務處理,若autoCommit=true會打開自動提交,一個條語句的執行失敗不會影響到其他語句。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章