mybatis 传入id_想深入理解MyBatis架构及原理实例分析 把握这些就够了
前言
MyBatis是目前非常流行的ORM框架,它的功能很強大,然而其實現卻比較簡單、優雅。本文主要講述MyBatis的架構設計思路,并且討論MyBatis的幾個核心部件,然后結合一個select查詢實例,深入代碼,來探究MyBatis的實現。
一、MyBatis的框架設計
注:上圖很大程度上參考了iteye 上的chenjc_it 所寫的博文[原理分析之二:框架整體設計] 中的MyBatis架構體圖,chenjc_it總結的非常好,贊一個!
1.接口層---和數據庫交互的方式
MyBatis和數據庫的交互有兩種方式:
a.使用傳統的MyBatis提供的API;
b. 使用Mapper接口
1.1.使用傳統的MyBatis提供的API
這是傳統的傳遞Statement Id 和查詢參數給SqlSession對象,使用SqlSession對象完成和數據庫的交互;MyBatis 提供了非常方便和簡單的API,供用戶實現對數據庫的增刪改查數據操作,以及對數據庫連接信息和MyBatis 自身配置信息的維護操作。
上述使用MyBatis 的方法,是創建一個和數據庫打交道的SqlSession對象,然后根據Statement Id和參數來操作數據庫,這種方式固然很簡單和實用,但是它不符合面向對象語言的概念和面向接口編程的編程習慣。由于面向接口的編程是面向對象的大趨勢,MyBatis 為了適應這一趨勢,增加了第二種使用MyBatis 支持接口(Interface)調用方式。
1.2. 使用Mapper接口
MyBatis 將配置文件中的每一個
根據MyBatis 的配置規范配置好后,通過SqlSession.getMapper(XXXMapper.class) 方法,MyBatis 會根據相應的接口聲明的方法信息,通過動態代理機制生成一個Mapper 實例,我們使用Mapper 接口的某一個方法時,MyBatis 會根據這個方法的方法名和參數類型,確定Statement Id,底層還是通過SqlSession.select("statementId",parameterObject);或者SqlSession.update("statementId",parameterObject); 等等來實現對數據庫的操作,(至于這里的動態機制是怎樣實現的,我將準備專門一片文章來討論,敬請關注~)
MyBatis 引用Mapper 接口這種調用方式,純粹是為了滿足面向接口編程的需要。(其實還有一個原因是在于,面向接口的編程,使得用戶在接口上可以使用注解來配置SQL語句,這樣就可以脫離XML配置文件,實現“0配置”)。
2.數據處理層
數據處理層可以說是MyBatis 的核心,從大的方面上講,它要完成三個功能:
a. 通過傳入參數構建動態SQL語句;
b. SQL語句的執行以及封裝查詢結果集成List
2.1.參數映射和動態SQL語句生成
動態語句生成可以說是MyBatis框架非常優雅的一個設計,MyBatis 通過傳入的參數值,使用 Ognl 來動態地構造SQL語句,使得MyBatis 有很強的靈活性和擴展性。
參數映射指的是對于java 數據類型和jdbc數據類型之間的轉換:這里有包括兩個過程:查詢階段,我們要將java類型的數據,轉換成jdbc類型的數據,通過 preparedStatement.setXXX()來設值;另一個就是對resultset查詢結果集的jdbcType 數據轉換成java 數據類型。
(至于具體的MyBatis是如何動態構建SQL語句的,我將準備專門一篇文章來討論,敬請關注~)
2.2. SQL語句的執行以及封裝查詢結果集成List
動態SQL語句生成之后,MyBatis 將執行SQL語句,并將可能返回的結果集轉換成List
3. 框架支撐層
3.1. 事務管理機制
事務管理機制對于ORM框架而言是不可缺少的一部分,事務管理機制的質量也是考量一個ORM框架是否優秀的一個標準.
3.2. 連接池管理機制
由于創建一個數據庫連接所占用的資源比較大, 對于數據吞吐量大和訪問量非常大的應用而言,連接池的設計就顯得非常重要.
3.3. 緩存機制
為了提高數據利用率和減小服務器和數據庫的壓力,MyBatis 會對于一些查詢提供會話級別的數據緩存,會將對某一次查詢,放置到SqlSession中,在允許的時間間隔內,對于完全相同的查詢,MyBatis 會直接將緩存結果返回給用戶,而不用再到數據庫中查找。(至于具體的MyBatis緩存機制,我將準備專門一篇文章來討論,敬請關注~)
二、MyBatis的主要構件及其相互關系
從MyBatis代碼實現的角度來看,MyBatis的主要的核心部件有以下幾個:
- SqlSession 作為MyBatis工作的主要頂層API,表示和數據庫交互的會話,完成必要數據庫增刪改查功能
- Executor MyBatis執行器,是MyBatis 調度的核心,負責SQL語句的生成和查詢緩存的維護
- StatementHandler 封裝了JDBC Statement操作,負責對JDBC statement 的操作,如設置參數、將Statement結果集轉換成List集合。
- ParameterHandler 負責對用戶傳遞的參數轉換成JDBC Statement 所需要的參數,
- ResultSetHandler 負責將JDBC返回的ResultSet結果集對象轉換成List類型的集合;
- TypeHandler 負責java數據類型和jdbc數據類型之間的映射和轉換
- MappedStatement MappedStatement維護了一條
- SqlSource 負責根據用戶傳遞的parameterObject,動態地生成SQL語句,將信息封裝到BoundSql對象中,并返回
- BoundSql 表示動態生成的SQL語句以及相應的參數信息
- Configuration MyBatis所有的配置信息都維持在Configuration對象之中。
(注:這里只是列出了我個人認為屬于核心的部件,請讀者不要先入為主,認為MyBatis就只有這些部件哦!每個人對MyBatis的理解不同,分析出的結果自然會有所不同,歡迎讀者提出質疑和不同的意見,我們共同探討~)
它們的關系如下圖所示:
三、從MyBatis一次select 查詢語句來分析MyBatis的架構設計
一、數據準備(非常熟悉和應用過MyBatis 的讀者可以迅速瀏覽此節即可)
2. 配置Mybatis的配置文件,命名為mybatisConfig.xml:
<?xml version="1.0" encoding="utf-8"? configuration5. 客戶端代碼:
package com.louis.mybatis.test; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import com.louis.mybatis.model.Employee; / * SqlSession 簡單查詢演示類 * @author louluan */ public class SelectDemo { public static void main(String[] args) throws Exception { /* * 1.加載mybatis的配置文件,初始化mybatis,創建出SqlSessionFactory,是創建SqlSession的工廠 * 這里只是為了演示的需要,SqlSessionFactory臨時創建出來,在實際的使用中,SqlSessionFactory只需要創建一次,當作單例來使用 */ InputStream inputStream = Resources.getResourceAsStream("mybatisConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(inputStream); //2. 從SqlSession工廠 SqlSessionFactory中創建一個SqlSession,進行數據庫操作 SqlSession sqlSession = factory.openSession(); //3.使用SqlSession查詢 Map二、SqlSession 的工作過程分析:
1. 開啟一個數據庫訪問會話---創建SqlSession對象:
SqlSession sqlSession = factory.openSession();MyBatis封裝了對數據庫的訪問,把對數據庫的會話和事務控制放到了SqlSession對象中。 ![201908092004_5.png][201908092004_5.png]#### 2. 為SqlSession傳遞一個配置的Sql語句 的Statement Id和參數,然后返回結果: ####List上述的"com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary",是配置在EmployeesMapper.xml 的Statement ID,params 是傳遞的查詢參數。
讓我們來看一下sqlSession.selectList()方法的定義:
publicMyBatis在初始化的時候,會將MyBatis的配置信息全部加載到內存中,使用org.apache.ibatis.session.Configuration實例來維護。使用者可以使用sqlSession.getConfiguration()方法來獲取。MyBatis的配置文件中配置信息的組織格式和內存中對象的組織格式幾乎完全對應的。上述例子中的
加載到內存中會生成一個對應的MappedStatement對象,然后會以key="com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary" ,value為MappedStatement對象的形式維護到Configuration的一個Map中。當以后需要使用的時候,只需要通過Id值來獲取就可以了。
從上述的代碼中我們可以看到SqlSession的職能是:
SqlSession根據Statement ID, 在mybatis配置對象Configuration中獲取到對應的MappedStatement對象,然后調用mybatis執行器來執行具體的操作。
3.MyBatis執行器Executor根據SqlSession傳遞的參數執行query()方法(由于代碼過長,讀者只需閱讀我注釋的地方即可):
/ * BaseExecutor 類部分代碼 * */ public / * *SimpleExecutor類的doQuery()方法實現 * */ public上述的Executor.query()方法幾經轉折,最后會創建一個StatementHandler對象,然后將必要的參數傳遞給StatementHandler,使用StatementHandler來完成對數據庫的查詢,最終返回List結果集。
從上面的代碼中我們可以看出,Executor的功能和作用是:
(1、根據傳遞的參數,完成SQL語句的動態解析,生成BoundSql對象,供StatementHandler使用;
(2、為查詢創建緩存,以提高性能(具體它的緩存機制不是本文的重點,我會單獨拿出來跟大家探討,感興趣的讀者可以關注我的其他博文);
(3、創建JDBC的Statement連接對象,傳遞給StatementHandler對象,返回List查詢結果。
4. StatementHandler對象負責設置Statement對象中的查詢參數、處理JDBC返回的resultSet,將resultSet加工為List 集合返回:
接著上面的Executor第六步,看一下:prepareStatement() 方法的實現:
/ * *SimpleExecutor類的doQuery()方法實現 * */ public
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); stmt = handler.prepare(connection); //對創建的Statement對象設置參數,即設置SQL 語句中 ? 設置為指定的參數 handler.parameterize(stmt); return stmt; }以上我們可以總結StatementHandler對象主要完成兩個工作:(1. 對于JDBC的PreparedStatement類型的對象,創建的過程中,我們使用的是SQL語句字符串會包含 若干個? 占位符,我們其后再對占位符進行設值。StatementHandler通過parameterize(statement)方法對Statement進行設值;(2.StatementHandler通過List // 每一個Mapping都有一個TypeHandler,根據TypeHandler來對preparedStatement進行設置參數 TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull(); // 設置參數 typeHandler.setParameter(ps, i + 1, value, jdbcType); } } }}從上述的代碼可以看到,StatementHandler 的parameterize(Statement) 方法調用了 ParameterHandler的setParameters(statement) 方法,ParameterHandler的setParameters(Statement)方法負責 根據我們輸入的參數,對statement對象的 ? 占位符處進行賦值。#### 6. StatementHandler 的List / * PreParedStatement類的query方法實現 */ public / *ResultSetHandler類的handleResultSets()方法實現 * */ public List從上述代碼我們可以看出,StatementHandler 的List
public List最后
由于上述的過程時序圖太過復雜,就不貼出來了,讀者可以下載MyBatis源碼, 使用Eclipse、Intellij IDEA、NetBeans 等IDE集成環境創建項目,Debug MyBatis源碼,一步步跟蹤MyBatis的實現,這樣對學習MyBatis框架很有幫助
大家看完有什么不懂的可以在下方留言討論.
謝謝你的觀看。
覺得文章對你有幫助的話記得關注我點個贊支持一下!
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的mybatis 传入id_想深入理解MyBatis架构及原理实例分析 把握这些就够了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 五边形创意画_绝了,自己做吊灯,创意满满
- 下一篇: svg text换行_5分钟看懂SVG反