<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我的家園

    我的家園

    1. 準(zhǔn)備工作

    ? 編寫(xiě)測(cè)試代碼(具體請(qǐng)參考《Mybatis入門(mén)示例》),設(shè)置斷點(diǎn),Debug模式運(yùn)行,具體代碼如下:?

    String resource = "mybatis.cfg.xml";
    
    Reader reader = Resources.getResourceAsReader(resource);
    
    SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
    
    SqlSession session = ssf.openSession();
    

    ???

    2.源碼分析

    我們此次就對(duì)上面的代碼進(jìn)行跟蹤和分析,let's go。

    首先我們按照順序先看看第一行和第二行代碼,看看它主要完成什么事情:

    String resource = "mybatis.cfg.xml";
    
    Reader reader = Resources.getResourceAsReader(resource);

    ????

    讀取Mybaits的主配置配置文件,并返回該文件的輸入流,我們知道Mybatis所有的SQL語(yǔ)句都寫(xiě)在XML配置文件里面,所以第一步就需要讀取這些XML配置文件,這個(gè)不難理解,關(guān)鍵是讀取文件后怎么存放。

    ?

    我們接著看第三行代碼(如下),該代碼主要是讀取配置文件流并將這些配置信息存放到Configuration類(lèi)中。

    SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);

    ?

    ????

    SqlSessionFactoryBuilderbuild的方法如下:

    public SqlSessionFactory build(Reader reader) {
        return build(reader, null, null);
      }

    ??

    其實(shí)是調(diào)用該類(lèi)的另一個(gè)build方法來(lái)執(zhí)行的,具體代碼如下:

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

    ??

    我們重點(diǎn)看一下里面兩行:

    //創(chuàng)建一個(gè)配置文件流的解析對(duì)象XMLConfigBuilder,其實(shí)這里是將環(huán)境和配置文件流賦予解析類(lèi)
    XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
    
    // 解析類(lèi)對(duì)配置文件進(jìn)行解析并將解析的內(nèi)容存放到Configuration對(duì)象中,并返回SqlSessionFactory
    return build(parser.parse());

    ??

    這里的XMLConfigBuilder初始化其實(shí)調(diào)用的代碼如下:?

    private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
        super(new Configuration());
    
        ErrorContext.instance().resource("SQL Mapper Configuration");
    
        this.configuration.setVariables(props);
    
        this.parsed = false;
    
        this.environment = environment;
    
        this.parser = parser; 
    
      }

    ?

    ?

    ?XMLConfigBuilderparse方法執(zhí)行代碼如下:??

    public Configuration parse() {
    
        if (parsed) {
    
          throw new BuilderException("Each MapperConfigParser can only be used once.");
    
        }
    
        parsed = true;
    
        parseConfiguration(parser.evalNode("/configuration"));
    
        return configuration;
    
      }

    ?

    解析的內(nèi)容主要是在parseConfiguration方法中,它主要完成的工作是讀取配置文件的各個(gè)節(jié)點(diǎn),然后將這些數(shù)據(jù)映射到內(nèi)存配置對(duì)象Configuration,我們看一下parseConfiguration方法內(nèi)容:?

    private void parseConfiguration(XNode root) {
    
        try {
    
          typeAliasesElement(root.evalNode("typeAliases"));
    
          pluginElement(root.evalNode("plugins"));
    
          objectFactoryElement(root.evalNode("objectFactory"));
    
          objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    
          propertiesElement(root.evalNode("properties"));
    
          settingsElement(root.evalNode("settings"));
    
          environmentsElement(root.evalNode("environments"));
    
          typeHandlerElement(root.evalNode("typeHandlers"));
    
          mapperElement(root.evalNode("mappers"));
    
        } catch (Exception e) {
    
          throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    
        }
    
      }

    最后的build方法其實(shí)是傳入配置對(duì)象進(jìn)去,創(chuàng)建DefaultSqlSessionFactory實(shí)例出來(lái). DefaultSqlSessionFactorySqlSessionFactory的默認(rèn)實(shí)現(xiàn).?
    public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }

    ???

    ?最后我們看一下第四行代碼:?

    SqlSession session = ssf.openSession();

    ?

    通過(guò)調(diào)用DefaultSqlSessionFactoryopenSession方法返回一個(gè)SqlSession實(shí)例,我們看一下具體是怎么得到一個(gè)SqlSession實(shí)例的。首先調(diào)用openSessionFromDataSource方法。??

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

    ?

    ?下面我們看一下openSessionFromDataSource方法的邏輯:??

    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Connection connection = null;
    
    try {
    
    //獲取配置信息里面的環(huán)境信息,這些環(huán)境信息都是包括使用哪種數(shù)據(jù)庫(kù),連接數(shù)據(jù)庫(kù)的信息,事務(wù)
    final Environment environment = configuration.getEnvironment();
    
    //根據(jù)環(huán)境信息關(guān)于數(shù)據(jù)庫(kù)的配置獲取數(shù)據(jù)源
    final DataSource dataSource = getDataSourceFromEnvironment(environment);
    
    //根據(jù)環(huán)境信息關(guān)于事務(wù)的配置獲取事務(wù)工廠(chǎng)
    TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    
          connection = dataSource.getConnection();
    
          if (level != null) {
    
            //設(shè)置連接的事務(wù)隔離級(jí)別
          connection.setTransactionIsolation(level.getLevel());
          }
    
          //對(duì)connection進(jìn)行包裝,使連接具備日志功能,這里用的是代理。
          connection = wrapConnection(connection);
    
          //從事務(wù)工廠(chǎng)獲取一個(gè)事務(wù)實(shí)例
          Transaction tx = transactionFactory.newTransaction(connection, autoCommit);
    
          //從配置信息中獲取一個(gè)執(zhí)行器實(shí)例
          Executor executor = configuration.newExecutor(tx, execType);
    
          //返回SqlSession的一個(gè)默認(rèn)實(shí)例
          return new DefaultSqlSession(configuration, executor, autoCommit);
    
        } catch (Exception e) {
    
          closeConnection(connection);
    
          throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    
        } finally {
    
          ErrorContext.instance().reset();
    
        }
    
      }

    ?

    傳入?yún)?shù)說(shuō)明:

    1ExecutorType:執(zhí)行類(lèi)型,ExecutorType主要有三種類(lèi)型:SIMPLE, REUSE, BATCH,默認(rèn)是SIMPLE,都在枚舉類(lèi)ExecutorType里面。

    2TransactionIsolationLevel:事務(wù)隔離級(jí)別,都在枚舉類(lèi)TransactionIsolationLevel中定義

    3autoCommit:是否自動(dòng)提交,主要是事務(wù)提交的設(shè)置。

    ?

    ?DefaultSqlSessionSqlSession的實(shí)現(xiàn)類(lèi),該類(lèi)主要提供操作數(shù)據(jù)庫(kù)的方法給開(kāi)發(fā)人員使用。

    ??

    這里總結(jié)一下上面的過(guò)程,總共由三個(gè)步驟:

    步驟一:讀取Ibatis的主配置文件,并將文件讀成文件流形式(InputStream)

    ?

    步驟二:從主配置文件流中讀取文件的各個(gè)節(jié)點(diǎn)信息并存放到Configuration對(duì)象中。讀取mappers節(jié)點(diǎn)的引用文件,并將這些文件的各個(gè)節(jié)點(diǎn)信息存放到Configuration對(duì)象。

    ?

    步驟三:根據(jù)Configuration對(duì)象的信息獲取數(shù)據(jù)庫(kù)連接,并設(shè)置連接的事務(wù)隔離級(jí)別等信息,將經(jīng)過(guò)包裝數(shù)據(jù)庫(kù)連接對(duì)象SqlSession接口返回,DefaultSqlSessionSqlSession的實(shí)現(xiàn)類(lèi),所以這里返回的是DefaultSqlSessionSqlSession接口里面就是對(duì)外提供的各種數(shù)據(jù)庫(kù)操作。






    只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲国产成人精品久久| 婷婷综合缴情亚洲狠狠尤物| 国产精成人品日日拍夜夜免费| 三级毛片在线免费观看| 日批视频网址免费观看| 精品国产麻豆免费人成网站| 免费精品一区二区三区第35| 可以免费观看的国产视频| 日本免费一区二区三区四区五六区| 曰批全过程免费视频在线观看无码| 暖暖免费在线中文日本| 88av免费观看入口在线| 性短视频在线观看免费不卡流畅| 日本精品人妻无码免费大全| 青青青青青青久久久免费观看| 免费a级毛片18以上观看精品| 亚洲人午夜射精精品日韩| 久久久久久久尹人综合网亚洲| 亚洲国语精品自产拍在线观看| 久久精品国产亚洲av麻豆小说| 久久精品国产亚洲av麻豆图片| 亚洲精品无码专区久久| 成人久久久观看免费毛片| 国产一级a毛一级a看免费人娇| 久久免费的精品国产V∧| 一二三四影视在线看片免费 | 国产在亚洲线视频观看| 一级全免费视频播放| 久久精品国产免费| 91九色精品国产免费| 国产美女无遮挡免费视频| 中文字幕亚洲综合久久菠萝蜜 | 免费在线观看黄网站| 亚洲午夜福利在线观看| 99亚洲精品高清一二区| 亚洲人av高清无码| 成av免费大片黄在线观看| 亚欧人成精品免费观看| 免费人成年轻人电影| 亚洲日本中文字幕| 亚洲6080yy久久无码产自国产|