Mybatis3源碼分析(6)簡單手寫思路及面試題

手寫基本流程

流程

  1. 定義接口 Mapper 和方法,用來調用數據庫操作。Mapper 接口操作數據庫需要通過代理類。
  2. 定義配置類對象 Configuration。
  3. 定義應用層的 API SqlSession。它有一個 getMapper()方法,我們會從配置類Configuration 裏面使用 Proxy.newProxyInatance()拿到一個代理對象MapperProxy。
  4. 有了代理對象 MapperProxy 之後,我們調用接口的任意方法,就是調用代理對象的 invoke()方法。
  5. 代理對象 MapperProxy 的 invoke()方法調用了 SqlSession 的 selectOne()。
  6. SqlSession 只是一個 API,還不是真正的 SQL 執行者,所以接下來會調用執行器 Executor 的 query()方法。
  7. 執行器 Executor 的 query()方法裏面就是對 JDBC 底層的 Statement 的封裝,最終實現對數據庫的操作,和結果的返回。
    附上手寫Mybatis github地址

ps:只是簡單的理解加深印象,裏面有很多不足。

面試分析

  1. resultType 和 resultMap 的區別?
resultType 是<select>標籤的一個屬性,適合簡單對象(POJO、JDK 自帶類型:Integer、String、Map 等)只能自動映射,適合單表簡單查詢。
resultMap 是一個可以被引用的標籤,適合複雜對象,可指定映射關係,適合關聯複合查詢。
  1. 標籤collection 和 標籤association 的區別?
association:一對一
collection:一對多、多對多
  1. PrepareStatement 和 Statement 的區別?
兩個都是接口,PrepareStatement 是繼承自 Statement 的;
Statement 處理靜態 SQL,PreparedStatement 主要用於執行帶參數的語句;
PreparedStatement 的 addBatch()方法一次性發送多個查詢給數據庫;
PS 相似 SQL 只編譯一次(對語句進行了緩存,相當於一個函數),減少編譯次數;
PS 可以防止 SQL 注入;
MyBatis 默認值:PREPARED 也就是PreparedStatement
  1. MyBatis 解決了什麼問題?
1) 資源管理(底層對象封裝和支持數據源)
2)結果集自動映射
3)SQL 與代碼分離,集中管理
4)參數映射和動態 SQL
5)其他:緩存、插件等
  1. MyBatis 編程式開發中的核心對象及其作用?
SqlSessionFactoryBuilder 創建工廠類
SqlSessionFactory 創建會話
SqlSession 提供操作接口
MapperProxy 代理 Mapper 接口後,用於找到 SQL 執行
  1. Java 類型和數據庫類型怎麼實現相互映射?
通過 TypeHandler,例如 Java 類型中的 String 要保存成 varchar,就會自動調用相應的 Handler。如果沒有系統自帶的 TypeHandler,也可以自定義--比如之前文章中寫的json轉對象的操作。
  1. SIMPLE/REUSE/BATCH 三種執行器的區別?
SimpleExecutor 使用後直接關閉 Statement:closeStatement(stmt);
ReuseExecutor 放在緩存中,可複用:PrepareStatement:getStatement();
BatchExecutor 支持複用且可以批量執行 update(),通過 ps.addBatch()實現handler.batch(stmt);
  1. MyBatis 一級緩存與二級緩存的區別?
一級緩存:在同一個會話(SqlSession)中共享,默認開啓,維護在 BaseExecutor中。
二級緩存:在同一個 namespace 共享,需要在 Mapper.xml 中開啓,維護在CachingExecutor 中。
  1. MyBaits 支持哪些數據源類型?
UNPOOLED:不帶連接池的數據源。
POOLED : 帶 連 接 池 的 數 據 源 , 在 PooledDataSource 中 維 護PooledConnection。
JNDI:使用容器的數據源,比如 Tomcat 配置了 C3P0。
自定義數據源:實現 DataSourceFactory 接口,返回一個 DataSource。當 MyBatis 集成到 Spring 中的時候,使用 Spring 的數據源
  1. 關聯查詢的延遲加載是怎麼實現的?
動態代理(JAVASSIST、CGLIB),在創建實體類對象時進行代理,在調用代理對象的相關方法時觸發二次查詢。
  1. MyBatis 翻頁的幾種方式和區別?
邏輯翻頁:通過 RowBounds 對象。
物理翻頁:通過改寫 SQL 語句,可用插件攔截 Executor 實現。
  1. 解析全局配置文件的時候,做了什麼?
創建 Configuration,設置 Configuration
解析 Mapper.xml,設置 MappedStatement
  1. 沒有實現類,MyBatis 的方法是怎麼執行的?
MapperProxy 代理,代理類的 invoke()方法中調用了 SqlSession.selectOne()
  1. 接口方法和映射器的 statement id 是怎麼綁定起來的?(怎麼根據接口方法拿到 SQL 語句的?)
MappedStatement 對象中存儲了 statement 和 SQL 的映射關係
  1. 四大對象是什麼時候創建的?
Executor:openSession()
StatementHandler、ResultsetHandler、ParameterHandler:
執行 SQL 時,在 SimpleExecutor 的 doQuery()中創建
  1. MyBatis 哪些地方用到了代理模式?
接口查找 SQL:MapperProxy
日誌輸出:ConnectionLogger、StatementLogger
連接池:PooledDataSource 管理的 PooledConnection
延遲加載:ProxyFactory(JAVASSIST、CGLIB)
插件:Plugin
Spring 集成:SqlSessionTemplate 的內部類 SqlSessionInterceptor
  1. MyBatis 插件怎麼編寫和使用?原理是什麼?
使用:繼承 Interceptor 接口,加上註解,在 mybatis-config.xml 中配置
原理:動態代理,責任鏈模式,使用 Plugin 創建代理對象
在被攔截對象的方法調用的時候,先走到 Plugin 的 invoke()方法,再走到Interceptor 實現類的 intercept()方法,
最後通過 Invocation.proceed()方法調用被攔截對象的原方法
  1. JDK 動態代理,代理能不能被代理?
能。層層代理先進後出
  1. MyBatis 集成到 Spring 的原理是什麼?
SqlSessionTemplate 中有內部類SqlSessionInterceptor對DefaultSqlSession進行代理;
MapperFactoryBean 繼 承 了 SqlSessionDaoSupport 獲 取SqlSessionTemplate;
接口註冊到 IOC 容器中的 beanClass 是 MapperFactoryBean。
  1. DefaulSqlSession 和 SqlSessionTemplate 的區別是什麼?
一個線程安全一個線程不安全
1)爲什麼 SqlSessionTemplate 是線程安全的?
其內部類 SqlSessionInterceptor 的 invoke()方法中的 getSqlSession()方法:如果當前線程已經有存在的 
SqlSession 對象,會在 ThreadLocal 的容器中拿到SqlSessionHolder,獲取 DefaultSqlSession。
如果沒有,則會 new 一個 SqlSession,並且綁定到 SqlSessionHolder,放到ThreadLocal 中。SqlSessionTemplate 
中在同一個事務中使用同一個 SqlSession。調用 closeSqlSession()關閉會話時,如果存在事務,減少 holder 的引用計數。否則直接關閉 SqlSession。
2) 在編程式的開發中,有什麼方法保證 SqlSession 的線程安全?
SqlSessionManager 同時實現了 SqlSessionFactory、SqlSession 接口,通過ThreadLocal 容器維護 SqlSession。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章