ORM框架之Mybatis(八):mybatis基礎(chǔ)代碼的了解和源碼跟蹤

mybatis使用在日常開(kāi)發(fā)中很簡(jiǎn)單,基本沒(méi)有門(mén)檻叮叹,都是和Spring直接集成蜕煌,然后把之前的一些配置copy到spring的配置文件中就可以使用鲸阻。具體mybatis的配置文件加載代碼玄呛,已經(jīng)SqlSession執(zhí)行的細(xì)節(jié)都被封裝到了框架中阅懦,符合面向?qū)ο缶幊蹋谴嬖谝粋€(gè)問(wèn)題就是那些細(xì)節(jié)的代碼慢慢都被遺忘徘铝。寫(xiě)這個(gè)博客就是記錄一下耳胎,以后忘記可以看看。僅此而已庭砍。

Mybatis配置文件的讀取和SqlSessionFactory的構(gòu)建

在mybatis中加載的基本的順序是讀取配置文件场晶,然后構(gòu)建SqlSessionFactory,通過(guò)SqlSessionFactory獲取Session實(shí)例怠缸,最后通過(guò)Session實(shí)例獲取到對(duì)應(yīng)Mapper的代理對(duì)象,通過(guò)代理對(duì)象來(lái)調(diào)用CRUD方法執(zhí)行數(shù)據(jù)的操作钳宪。

SqlSessionFactory構(gòu)建
public class UserService {

    private static SqlSessionFactory sqlSessionFactory;
    //加載xml文件
    static {
        InputStream inputStream = null;
        try {
            //讀取配置文件
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            //構(gòu)建SqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //關(guān)閉流
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

先將Mybatis核心配置文件mybatis-config.xml讀取到流中揭北,然后交給SqlSessionFactoryBuilder構(gòu)建SqlSessionFactory對(duì)象扳炬,在構(gòu)建前會(huì)對(duì)核心配置文件進(jìn)行一系列的分析,并將分析的內(nèi)容放到Configuration實(shí)例中搔体,分析的過(guò)程之前的博客中有恨樟,可以翻一翻參考一下。

到這里是sqlSessionFactory構(gòu)建完成疚俱,接下來(lái)看如何使用劝术。

SqlSession、Mapper的獲取以及使用
public void insert() {
    //獲取SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //獲取UserMapper
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    UserMode mode = new UserMode();
    mode.setUserName("Joker");
    mode.setUserPhone("15612341234");
    mode.setUserAge(20);
    //調(diào)用插入方法
    mapper.insert(mode);
}

這里實(shí)現(xiàn)的邏輯的方法不難呆奕,關(guān)鍵是在于SqlSessionUserMapper的獲取养晋,這里和大家一起看看源碼。

SqlSession獲取源碼

SqlSessionFactory是個(gè)接口梁钾,其實(shí)現(xiàn)是DefaultSqlSessionFactory绳泉,在這個(gè)類(lèi)中有各種獲取SqlSession實(shí)例的方法,根據(jù)上面的實(shí)例代碼姆泻,找到openSession方法的實(shí)現(xiàn)零酪。

public SqlSession openSession() {
   /**
   * configuration中獲取默認(rèn)的Executor執(zhí)行器的類(lèi)型
   * 第二個(gè)參數(shù)是事務(wù)隔離級(jí)別
   * 第三個(gè)參數(shù)表示是否自動(dòng)提交,默認(rèn)值是false
   **/
  return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

執(zhí)行器Executor類(lèi)型有多種拇勃,如果在mapper.xml文件中沒(méi)有特殊的配置基本使用的都是默認(rèn)的執(zhí)行器SimpleExecutor四苇。事務(wù)隔離級(jí)別和是否自動(dòng)提交都是使用默認(rèn)的值。

進(jìn)入到openSessionFromDataSource方法中后方咆,從上面的傳入?yún)?shù)可以知道蛔琅,在這個(gè)方法中就是根據(jù)Executor執(zhí)行器的類(lèi)型創(chuàng)建相對(duì)應(yīng)的實(shí)例,同時(shí)也會(huì)根據(jù)數(shù)據(jù)相關(guān)的參數(shù)構(gòu)建出對(duì)應(yīng)的事務(wù)管理器峻呛。待著兩個(gè)實(shí)例構(gòu)建結(jié)束罗售,就會(huì)根據(jù)這兩個(gè)實(shí)例去構(gòu)建最終需要的SqlSession實(shí)例。源碼如下:

/**
 * 構(gòu)建Session
 * @param execType 執(zhí)行器類(lèi)型
 * @param level 事務(wù)隔離界別
 * @param autoCommit 是否自動(dòng)提交
 * @return
 */
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
        //configuration獲取環(huán)境配置信息
        final Environment environment = configuration.getEnvironment();
        //事務(wù)管理器工廠
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        //創(chuàng)建事務(wù)管理器
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        //創(chuàng)建執(zhí)行器executor
        final Executor executor = configuration.newExecutor(tx, execType);
        //構(gòu)建Session
        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();
    }
}

基本的流程和上面的解釋一樣钩述。至于再深入的代碼就不再詳盡的貼出來(lái)啦(源碼的內(nèi)容太多寨躁,入口已提供,可以自己跟進(jìn)去詳細(xì)的了解)牙勘,但是下面可以大概的說(shuō)一下职恳。

mybatis-config.xml核心配置文件中有個(gè)environment標(biāo)簽,這個(gè)標(biāo)簽中會(huì)配置相應(yīng)的數(shù)據(jù)源信息和事務(wù)管理器的信息方面。在源碼中將這些參數(shù)傳入到事務(wù)管理器工廠中放钦,構(gòu)建工廠對(duì)象TransactionFactory,接著調(diào)用其創(chuàng)建事務(wù)管理器對(duì)象的方法恭金。到這里事務(wù)管理器實(shí)例創(chuàng)建完成操禀。

然后根據(jù)構(gòu)建好的事務(wù)管理器和執(zhí)行器類(lèi)型去構(gòu)建執(zhí)行器對(duì)象,執(zhí)行器對(duì)象的類(lèi)型共有三種横腿,從ExecutorType枚舉類(lèi)中可以看到颓屑,分別是是BATCH批處理模式斤寂,REUSE復(fù)用模式,SIMPLE簡(jiǎn)單模式揪惦。在newExecutor方法中對(duì)執(zhí)行器類(lèi)型做了判斷遍搞,當(dāng)不是批處理或者復(fù)用模式的時(shí)候就默認(rèn)使用簡(jiǎn)單模式,當(dāng)然后面還有對(duì)cacheEnabled的判斷器腋,如果支持緩存溪猿,還需要對(duì)上面的SimpleExecutor包裝一層,然后就是對(duì)整個(gè)執(zhí)行鏈的包裝纫塌。至此執(zhí)行器構(gòu)建完成诊县。(執(zhí)行器構(gòu)建的過(guò)程使用的是裝飾器模式)

事務(wù)管理器、執(zhí)行器構(gòu)建結(jié)束护戳,使用Configuration翎冲、執(zhí)行器和是否自動(dòng)提交參數(shù),構(gòu)建SqlSession對(duì)象媳荒,這個(gè)過(guò)程很簡(jiǎn)單抗悍,就是將這些參數(shù)設(shè)置到SqlSession對(duì)象成員變量中。

Mapper獲取源碼

Mapper本身只是一個(gè)接口钳枕,在從SqlSession對(duì)象中get獲取對(duì)象的時(shí)候缴渊,是使用的動(dòng)態(tài)代理,在mybatis源碼中有一個(gè)模塊叫做binding鱼炒,在這里面有具體做動(dòng)態(tài)代理的實(shí)現(xiàn)衔沼。看源碼:

public <T> T getMapper(Class<T> type) {
    //通過(guò)configuration構(gòu)建Mapper實(shí)例
    return configuration.<T>getMapper(type, this);
}

SqlSession中有個(gè)Configuration實(shí)例昔瞧,通過(guò)這個(gè)實(shí)例使用的getMapper方法構(gòu)建Mapper代理對(duì)象指蚁,進(jìn)入后會(huì)調(diào)用MapperRegistry(Mapper注冊(cè)器),在注冊(cè)器里面會(huì)構(gòu)建MapperProxyFactory工廠類(lèi)自晰,然后通過(guò)工廠類(lèi)的newInstance方法構(gòu)建具體的代理對(duì)象MapperProxy凝化。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //根據(jù)type到knowMappers中獲取MapperProxyFactory實(shí)例
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
        //mapperProxyFactory生成對(duì)象實(shí)例
        return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
        throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

通過(guò)這里就完成了Mapper代理對(duì)象的創(chuàng)建,并返回酬荞。

insert方法調(diào)用

mapper.xml文件的結(jié)果過(guò)程中搓劫,有對(duì)應(yīng)的方法解析,每個(gè)方法解析后會(huì)對(duì)應(yīng)有一個(gè)MappedStatement混巧。最終會(huì)調(diào)用到執(zhí)行器Executor中的update方法枪向。整個(gè)執(zhí)行的過(guò)程相對(duì)比較復(fù)雜一點(diǎn),這里就不貼出源碼咧党,有興趣的可以看一下秘蛔,篇幅有限,在后續(xù)的博客文章里面再詳細(xì)說(shuō)Executor執(zhí)行各種方法的方式和流程。

本文作者:程序猿楊鮑
版權(quán)歸作者所有缠犀,轉(zhuǎn)載請(qǐng)注明出處

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末数苫,一起剝皮案震驚了整個(gè)濱河市聪舒,隨后出現(xiàn)的幾起案子辨液,更是在濱河造成了極大的恐慌,老刑警劉巖箱残,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滔迈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡被辑,警方通過(guò)查閱死者的電腦和手機(jī)燎悍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盼理,“玉大人谈山,你說(shuō)我怎么就攤上這事『暾” “怎么了奏路?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)臊诊。 經(jīng)常有香客問(wèn)我鸽粉,道長(zhǎng),這世上最難降的妖魔是什么抓艳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任触机,我火速辦了婚禮,結(jié)果婚禮上玷或,老公的妹妹穿的比我還像新娘儡首。我一直安慰自己,他們只是感情好偏友,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布蔬胯。 她就那樣靜靜地躺著,像睡著了一般约谈。 火紅的嫁衣襯著肌膚如雪笔宿。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天棱诱,我揣著相機(jī)與錄音泼橘,去河邊找鬼。 笑死迈勋,一個(gè)胖子當(dāng)著我的面吹牛炬灭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播靡菇,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼重归,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼米愿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鼻吮,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤育苟,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后椎木,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體违柏,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年香椎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漱竖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡畜伐,死狀恐怖馍惹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玛界,我是刑警寧澤万矾,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站脚仔,受9級(jí)特大地震影響勤众,放射性物質(zhì)發(fā)生泄漏宵蕉。R本人自食惡果不足惜鳞滨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望衅澈。 院中可真熱鬧猎醇,春花似錦窥突、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至沦疾,卻和暖如春称近,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哮塞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工刨秆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人忆畅。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓衡未,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缓醋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容