mybatis源碼分析

1、mybatis源碼分析面試

1.mybatis功能架構sql

2. SQL調用過程(mybatis工做原理)數據庫

mybatis經過配置文件建立sqlsessionFactory,sqlsessionFactory根據配置文件,配置文件來源於兩個方面:一個是xml,一個是Java中的註解,獲取sqlSession。SQLSession包含了執行sql語句的全部方法,能夠經過SQLSession直接運行映射的sql語句,完成對數據的增刪改查和事物的提交工做,用完以後關閉SQLSession。 緩存

3. mybatis的SqlSessionFactory 與 SqlSession.安全

(1)首先,SqlSessionFactoryBuilder去讀取mybatis的配置文件,而後build一個DefaultSqlSessionFactory。session

(2)當咱們獲取到SqlSessionFactory以後,就能夠經過SqlSessionFactory去獲取SqlSession對象。mybatis

4. 利器之MapperProxy:架構

在mybatis中,經過MapperProxy動態代理我們的dao(mapper), 也就是說, 當我們執行本身寫的dao裏面的方法的時候,實際上是對應的mapperProxy在代理。app

(1)經過SqlSession從Configuration中獲取。框架

(2)SqlSession把包袱甩給了Configuration, 接下來就看看Configuration。

(3)Configuration不要這燙手的山芋,接着甩給了MapperRegistry, 那咱看看MapperRegistry。

(4)MapperRegistry經過調用newInstance動態代理咱們寫的dao接口。

5.Excutor

6.mybatis的緩存

6.1 一級緩存的做用域是SqlSession

Executor接口的實現類是由Configuration構造的:

public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
    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, autoCommit);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

最後咱們發現若是cacheEnabled這個屬性爲true的話,那麼executor會被包一層裝飾器,這個裝飾器是CachingExecutor。其中cacheEnabled這個屬性是mybatis總配置文件中settings節點中cacheEnabled子節點的值,默認就是true,也就是說咱們在mybatis總配置文件中不配cacheEnabled的話,它也是默認爲打開的。

CachingExecutor執行sql的時候到底作了什麼?

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    Cache cache = ms.getCache();//這兒執行的是二級緩存
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) { 
        ensureNoOutParams(ms, parameterObject, boundSql);
        if (!dirty) {
          cache.getReadWriteLock().readLock().lock();
          try {
            @SuppressWarnings("unchecked")
            List<E> cachedList = (List<E>) cache.getObject(key);
            if (cachedList != null) return cachedList;
          } finally {
            cache.getReadWriteLock().readLock().unlock();
          }
        }
        List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
        return list;
      }
    }
    return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

因爲咱們沒有開啓二級緩存(二級緩存的內容下面會分析),所以這裏執行了最後一句話。因此一級緩存最重要的代碼就是BaseExecutor的query方法! 這個localCache就是一級緩存!

接下來咱們看下爲什麼執行新增或更新或刪除操做,一級緩存就會被清除這個問題。

CachingExecutor的update方法

public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms);//這清除的是二級緩存
    return delegate.update(ms, parameterObject);
}

BaseExecutor的update方法:

public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (closed) throw new ExecutorException("Executor was closed.");
    clearLocalCache();
    return doUpdate(ms, parameter);
}

6.2 二級緩存

二級緩存的做用域是全局,換句話說,二級緩存已經脫離SqlSession的控制了。二級緩存的做用域是全局的,二級緩存在SqlSession關閉或提交以後纔會生效。

本文就說下最簡單的配置,在mapper文件上加上這句配置便可:<cache/>

2、面試相關

1.mybatis是什麼? 
mybatis是一個優秀的持久層框架,他對jdbc操做數據庫的過程進行了封裝,使開發着只用關注sql自己,不用去關注例如註冊驅動,加載連接,獲得statement,處理結果集等複雜的過程。 
mybatis經過xml或者註解的方式,將要執行的各類sql語句配置起來,並經過Java對象和statement中的sql語句映射生成最終的sql語句,最後由mybatis框架執行sql語句,並將結果映射成Java對象返回。 

2.mybatis解決的問題

  • 使用數據庫鏈接池管理連接,避免了頻繁建立了、關閉連接,浪費資源,影響性能的問題。
  • 用xml管理sql語句,讓Java代碼和sql語句分離,使得代碼更易維護。
  • 解決了sql語句參數不定的問題。xml中能夠經過where條件決定sql語句的條件參數。mybatis將Java對象映射到sql語句,經過statement的parameterType定義輸入參數的類型。
  • mybatis自動將結果集封裝成Java對象, 經過statement的resultType定義輸出的類型。避免了因sql變化,對結果集處理麻煩的問題。

3. #{}和${}的區別是什麼?

#{}是預編譯處理,${}是字符串替換。 Mybatis在處理#{}時,會將sql中的#{}替換爲?號,調用PreparedStatement的set方法來賦值; Mybatis在處理${}時,就是把${}替換成變量的值。 使用#{}能夠有效的防止SQL注入,提升系統安全性。

4.Mybatis是如何進行分頁的?分頁插件的原理是什麼?

Mybatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁,而非物理分頁,能夠在sql內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可使用分頁插件來完成物理分頁。 分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的sql,而後重寫sql,根據dialect方言,添加對應的物理分頁語句和物理分頁參數。

5.什麼是延遲加載

  1. 延遲加載的條件:resultMap能夠實現高級映射(使用association、collection實現一對一及一對多映射),association、collection具有延遲加載功能。
  2. 延遲加載的好處:
    先從單表查詢、須要時再從關聯表去關聯查詢,大大提升 數據庫性能,由於查詢單表要比關聯查詢多張錶速度要快。
  3. 延遲加載的實例:
    若是查詢訂單而且關聯查詢用戶信息。若是先查詢訂單信息便可知足要求,當咱們須要查詢用戶信息時再查詢用戶信息。把對用戶信息的按需去查詢就是延遲加載。

6.Hibernate3與 MyBatis3.1的比較

二者相同點

Hibernate與 MyBatis均可以是經過SessionFactoryBuider由XML配置文件生成SessionFactory,而後由 SessionFactory 生成Session,最後由Session來開啓執行事務和SQL語句。其中 SessionFactoryBuider,SessionFactory,Session的生命週期都是差很少的。

Hibernate和MyBatis都支持JDBC和JTA事務處理。

Mybatis優點

MyBatis能夠進行更爲細緻的SQL優化,能夠減小查詢字段。

MyBatis容易掌握,而Hibernate門檻較高。

Hibernate優點

Hibernate的DAO層開發比MyBatis簡單,Mybatis須要維護SQL和結果映射。

Hibernate對對象的維護和緩存要比MyBatis好,對增刪改查的對象的維護要方便。

Hibernate數據庫移植性很好,MyBatis的數據庫移植性很差,不一樣的數據庫須要寫不一樣SQL。

Hibernate有更好的二級緩存機制。Hibernate緩存分爲:

一級緩存:session共享(save、update、saveOrupdate、load、get、list) 用於處理當前的單元操做.

二級緩存:sessionFactory共享.(常常讀不多被修改,若是使用二級緩存能夠提升性能.)

MyBatis自己提供的緩存機制不佳。MyBatis 包含一個很是強大的查詢緩存特性,它能夠很是方便地配置和定製。默認狀況下是沒有開啓緩存的,除了局部 的 session 緩存,能夠加強變現並且處理循環依賴也是必須的。要開啓二級緩存,你須要在你的 SQL 映射文件中添加一行:  <cache/>

hibernate中session打開和關閉由sessionFactory的getSession()來管理session的打開和關閉。

第三方緩存實現:cache、Map等;

相關文章
相關標籤/搜索