mybatis原理,配置介紹及原始碼分析

kinnylee發表於2018-10-31

前言

mybatis核心元件有哪些?它是工作原理是什麼?

mybatis配置檔案各個引數是什麼含義?

mybatis只新增了介面類,沒有實現類,為什麼可以直接查詢呢?

mybatis的mapper對映檔案各個引數又是什麼含義?

mybatis-spring提供哪些機制簡化了原生mybatis?

mybatis-springboot-starter又是如何簡化進一步讓mybatis使用如此方便?程式碼呼叫流程是怎麼樣的?

目錄

jdbc介紹

mybatis介紹

mybatis-spring

mybatis-spring-boot-starter

mybatis原始碼分析

mybatis程式碼生成工具mybatis-generator

mybatis分頁外掛pagehelper

一. jdbc介紹

1. 概述

  • jdbc是sun公司提出的一系列對資料庫操作的規範
  • java程式對資料庫的連線都通過jdbc規範進行,它統一了介面,使用者在使用時無需關心各個資料庫廠商底層的差異
  • 不同資料庫底層具體實現由資料庫廠商實現,也就是資料庫驅動程式

2. 使用jdbc進行開發的流程

  • 載入驅動,Driver介面
  • 建立連線,Connection介面
  • 建立執行SQL的Statement
  • 通過Statement執行SQL,執行結果返回到ResultSet並處理
  • 釋放資源

3. 總結與反思

  • jdbc程式設計工作量大,需要處理連線,事務,資料型別,各種Connection,Statement,ResultSet,關閉連線等等
  • 實際開發中不會直接使用jdbc程式設計,而是使用物件關係模型(ORM)框架。

二. mybatis介紹

1. 概述

mybatis是一款優秀的持久層框架,支援定製SQL語句,避免了幾乎所有JDBC程式碼和手動設定引數,結果集獲取

2. 如何使用

  • pom檔案中新增mybatis的依賴
  • 讀取配置檔案,將配置資訊傳給SqlSessionFactoryBuilder的build方法,構造出SqlSessionFactory
  • 用SqlSessionFactory取得SqlSession
  • 呼叫SqlSession的getMapper得到mapper介面
  • 呼叫mapper介面中的增刪該查方法運算元據庫

3. 核心元件和API

  • SqlSession:mybatis最核心的元件,可以傳送sql去執行並返回結果,也可以獲取Mapper介面。類似於jdbc的Connection物件
  • SqlSessionFactory:建立SqlSession的工廠類,包含所有建立SqlSession例項的方法
  • SqlSessionFactoryBuilder: 根據配置資訊Configuration或程式碼構建SqlSessionFactory物件
  • SQL Mapper:由Java介面和xml檔案構成,並給出對應的sql和對映規則,負責傳送sql執行並返回

SqlSessionFactoryBuilder

  • 一旦建立了SqlSessionFactory之後,就不再需要它了,最佳作用域是區域性變數
  • 包含的函式如下圖所示,允許通過不同的方法建立SqlSessionFactory
  • configuration 類包含你可能需要了解 SqlSessionFactory 例項的所有內容
SqlSessionFactory build(InputStream inputStream)SqlSessionFactory build(InputStream inputStream, String environment)SqlSessionFactory build(InputStream inputStream, Properties properties)SqlSessionFactory build(InputStream inputStream, String env, Properties props)SqlSessionFactory build(Configuration config)複製程式碼

SqlSessionFactory

  • 每個Mybatis應用都是以SqlSessionFactory例項為中心的,它的任務是建立SqlSession
  • 每個資料庫對應一個,在MyBatis應用的整個生命週期中,設計為單例或靜態單例模式最佳
  • 構建方法:xml配置方式和程式碼方式
  • 包含的函式如下圖所示
//預設獲取的方式,不自動提交(開啟事務)SqlSession openSession()//是否自動提交SqlSession openSession(boolean autoCommit)SqlSession openSession(Connection connection)//事務的隔離級別:None,RU,RC,RR,SerialSqlSession openSession(TransactionIsolationLevel level)//查詢型別:simple,batch,reuseSqlSession openSession(ExecutorType execType,TransactionIsolationLevel level)SqlSession openSession(ExecutorType execType)SqlSession openSession(ExecutorType execType, boolean autoCommit)SqlSession openSession(ExecutorType execType, Connection connection)//獲取mybatis配置資訊Configuration getConfiguration();
複製程式碼

SqlSession

  • 每個執行緒都應該有他自己的SqlSession例項
  • 是一個介面類,扮演門面的作用,真正幹活的是Executor介面
  • 生命週期在請求資料庫處理事務的過程中,不是執行緒安全的物件,不能作為類的靜態變數。多執行緒要小心
  • 每次使用時開啟一個SqlSession,操作完就關閉它
//帶引數的增刪改查方法<
T>
T selectOne(String statement, Object parameter)<
E>
List<
E>
selectList(String statement, Object parameter)<
K,V>
Map<
K,V>
selectMap(String statement, Object parameter, String mapKey)int insert(String statement, Object parameter)int update(String statement, Object parameter)int delete(String statement, Object parameter)//不帶引數的增刪改查方法<
T>
T selectOne(String statement)<
E>
List<
E>
selectList(String statement)<
K,V>
Map<
K,V>
selectMap(String statement, String mapKey)int insert(String statement)int update(String statement)int delete(String statement)//高階版本的增刪該查方法,支援自定義返回行數和結果控制<
E>
List<
E>
selectList (String statement, Object parameter, RowBounds rowBounds)<
K,V>
Map<
K,V>
selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)void select (String statement, Object parameter, ResultHandler<
T>
handler)
void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler<
T>
handler)
//事務控制相關方法void commit()void commit(boolean force)void rollback()void rollback(boolean force)//清除快取。mybatis提供了本地快取和二級快取void clearCache()//關閉sessionvoid close()//獲得configuration例項Configuration getConfiguration()//獲得對映器<
T>
T getMapper(Class<
T>
type)
複製程式碼

mapper

  • 用來繫結對映SQL語句的介面
  • 由java介面和xml組成,提供的功能有
    • 定義引數型別
    • 描述快取
    • 描述sql語句
    • 定義查詢結果和POJO的對映關係
  • 生命週期小於SqlSession,如同jdb中一條sql的執行
  • 用過之後不需要顯示關閉mapper

4. mybatis配置說明

4.1 主配置檔案

所有支援的配置項介紹文件:mybatis配置檔案說明,最外層標籤為configuration,子標籤有:

  • propertiess, 可以外部配置且動態替換

  • typeAliases,定義別名。用於減少冗長的類限定名,只和xml配置有關

    <
    typeAlias>
    <
    typeAlia alias="role" type="XXX"/>
    <
    package name="xxx"/>
    <
    /typeAlias>
    複製程式碼
  • mappers,定義對映器,告訴mybatis去哪裡找對映器

    <
    mappers>
    <
    mapper resource="xxx"/>
    <
    mapper url="file:://xxx"/>
    <
    mapper class="xxx"/>
    <
    !--包內的所有介面都註冊為對映器-->
    <
    package name="xxx" />
    <
    /mappers>
    複製程式碼
  • typeHandlers,用於將獲取的值轉化為合適的java型別

    <
    typeHandlers>
    <
    typeHandler handler="xxx">
    <
    /typeHandlers>
    複製程式碼

    mybatis提供了很多預設的型別處理器,簡單列舉幾個

    • BooleanTypeHandler:boolean-bool
    • StringTypeHandler:String-varchar,char
    • IntegerTypeHandler:Integer-int
    • DateTypeHandler:Date-timestamp
    • EnumTypeHandler:儲存列舉類字串
    • EnumOrdinalTypeHandler:儲存列舉類下標

    如果標準處理器滿足不了需求,可自定義處理器選擇性對映到某個JDBC型別,具體步驟:

    • 實現org.apache.ibatis.type.TypeHandler介面
    • 指定該處理器要對映的jdbc型別:配置檔案typeHandler中指定jdbc=“xxx”,或者處理類上使用@MappedJdbcTypes
    • 指定該處理器要對映的java型別:
  • environments,定義瞭如何配置資料庫環境資訊

    <
    environments>
    <
    environment>
    <
    transactionManager type="JDBC">
    <
    /transactionManager>
    <
    dataSource type="POOLED">
    <
    property name="url" value="xxx">
    ... <
    /dataSource>
    <
    /environment>
    <
    /environments>
    複製程式碼
  • settings,很重要的引數

    <
    settings>
    <
    !--全域性開啟對映器已經配置的任何快取-->
    <
    setting name="cacheEnabled" value="true"/>
    <
    !--延遲載入的全域性開關-->
    <
    setting name="lazyLoadingEnabled" value="true"/>
    <
    !--是否執行單一語句返回多條結果集-->
    <
    setting name="multipleResultSetsEnabled" value="true"/>
    <
    !--列標籤代替列名-->
    <
    setting name="useColumnLabel" value="true"/>
    <
    !--執行jdbc支援自增長主鍵-->
    <
    setting name="useGeneratedKeys" value="false"/>
    <
    !--如何自動對映列到欄位屬性-->
    <
    setting name="autoMappingBehavior" value="PARTIAL"/>
    <
    !---->
    <
    setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
    <
    !--預設的執行器-->
    <
    setting name="defaultExecutorType" value="SIMPLE"/>
    <
    !--超時時間-->
    <
    setting name="defaultStatementTimeout" value="25"/>
    <
    !--日誌框架,可選值有:SLF4J,LOG4J,JDK_LOGGING,COMMONS_LOGGING,STDOUT_LOGGING,NO_LOGGING-->
    <
    setting name="logImpl" value="LOG4J"/>
    <
    !---->
    <
    setting name="defaultFetchSize" value="100"/>
    <
    !---->
    <
    setting name="safeRowBoundsEnabled" value="false"/>
    <
    !--是否開啟自動駝峰命名規則:下劃線列名轉駝峰變數名-->
    <
    setting name="mapUnderscoreToCamelCase" value="false"/>
    <
    !---->
    <
    setting name="localCacheScope" value="SESSION"/>
    <
    !---->
    <
    setting name="jdbcTypeForNull" value="OTHER"/>
    <
    !---->
    <
    setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    <
    /settings>
    複製程式碼
  • objectFactory:建立結果物件的工廠類,可自定義覆蓋預設的

    <
    objectFactory type="XXX">
    <
    property name="xx", value="xx"/>
    <
    /objectFactory>
    複製程式碼
  • plugins:外掛執行定義攔截器,攔截mybatis執行過程中的某些呼叫

4.2 Mapper對映檔案

對映檔案定義了介面要執行的sql語句,所有支援的對映檔案介紹文件:mybatis對映檔案說明

  • select
    <
    select id="呼叫介面的函式名稱,唯一標識" parameterType="引數型別,可省略,會根據typehandler自動推斷" parameterMap="被廢棄的選項" resultType="返回結果的型別,不能與resultMap同時存在" resultMap="返回結果的外部集合對映,不能與resultType同時存在。resultType為bean時,底層使用了resultMap" flushCache="設定為true表示任何時候呼叫都會清除本地和二級快取,預設false" useCache="是否開啟本地和二級快取,預設為true" timeout="驅動等待資料庫響應時間,預設為unset,依賴驅動" fetchSize="驅動每次批量返回結果數" statementType="預設preparedStatement" resultSetType="結果集型別,逗號分開">
    select id, name from table_name where id = #{id
    }<
    /select>
    複製程式碼
  • insert/update/delete:很多屬性同insert
    <
    insert ... useGeneratedKeys="是否取出資料庫自增長得到的id,預設false" keyProperty=“generatedKey的目標屬性欄位” keyColumn=“generatedKey的目標列名,主鍵列不是第一列需要設定” >
    <
    /insert>
    複製程式碼
  • sql:定義可重用的sql語句
    <
    sql id="xxx">
    <
    /sql>
    <
    !--呼叫的地方-->
    <
    include refid="xxx"/>
    複製程式碼
  • resultMap:mybatis只最重要最強大的元素
    <
    resultMap>
    <
    !--注入結果到構造方法中-->
    <
    constructor>
    <
    idArg column="" javatype="">
    <
    arg>
    <
    /constructor>
    <
    !--複雜型別的關聯-->
    <
    association>
    <
    /association>
    <
    !--複雜型別的集合-->
    <
    collection>
    <
    /collection>
    <
    /resultMap>
    複製程式碼
  • cache:開啟快取,預設情況下是不開啟快取的,除了區域性session
    <
    !--開啟可讀可寫快取,所有select都被快取,insert,delete和update重新整理快取,-->
    <
    cache <
    !--回收策略:包括LRU(預設),FIFO,SOFT,WEAK-->
    eviction="LRU" <
    !--重新整理時間,單位毫秒-->
    flushInternval="60000" readOnly="true" <
    !--快取儲存的引用數量,預設1024-->
    size="512"/>
    <
    cache type="自定義快取,必須實現org.mybatis.cache.Cache介面"/>
    複製程式碼
  • cache-ref:引用另外一個快取

5. 動態SQL

動態SQL:用於根據條件包含where字句的一部分。動態SQL包括if,choose,trim,foreach

    <
select/insert id="xx">
select id, name, status from table_name where status = #{status
} <
!--普通的條件判斷語句-->
<
if test="name != null">
and name like #{name
} <
/if>
<
!--條件分支語句,類似與switch-->
<
choose>
<
when test="name != null">
<
/when>
<
otherwise>
<
/otherwise>
<
/choose>
<
!--會自動去除條件不滿足時多餘的where,and,or等關鍵字-->
<
where>
<
/where>
<
!--自定義去除某些符號的功能-->
<
trim prefix="WHERE" prefixOverrides="AND|OR">
<
/trim>
<
set>
<
if>
<
/set>
<
foreach item="" index="" collection="">
<
/foreach>
<
/select>
複製程式碼

三. Mybatis Spring

1. 概述

  • 無縫的將mybatis整合到spring中,使用這個類庫,spring會載入必要到工廠類和session類
  • 允許mybatis參與到spring的事務管理中,利用了spring的DataSourceTransactionManger
  • 使用mybatis-spring,需要在上下文中定義sqlSessionFactory和至少一個資料對映器類

2. 如何使用

  • pom中新增mybatis-spring依賴
  • spring的xml檔案中傳入資料來源,並配置sqlSessionFactory
  • spring的xml檔案中配置mapper對映介面
  • 業務程式碼中獲取自動注入到容器的對映介面,並呼叫增刪改查方法運算元據庫

3. SqlSessionFactoryBean

  • 前面介紹原生Mybatis中,通過SqlSessionFactoryBuilder建立SqlSessionFactory。而mybati-spring中由SqlSessionFactoryBean建立
    <
    bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <
    !--必須的屬性,配置資料來源-->
    <
    property name="dataSource" ref="dataSource" />
    <
    !--可選屬性,配置對映檔案路徑-->
    <
    property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
    <
    /bean>
    複製程式碼
  • SqlSessionFactoryBean實現了spring的FactoryBean介面
  • 它必須注入dataSource屬性

4. 配置事務

<
bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<
!--資料來源必須和SqlSessionFactoryBean配置的資料來源一致-->
<
property name="dataSource" ref="dataSource" />
<
/bean>
複製程式碼

5. 使用SqlSession

  • 原生mybatis中,通過SqlSessionFactory獲取SqlSession,在mybatis-spring中,不再需要直接使用SqlSessionFactory,因為SqlSession已經以執行緒安全的Bean的方式自動注入了
  • SqlSessionTemplate是mybatis-spring的核心,實現了SqlSession介面,負責管理SqlSession。它是執行緒安全的,可以被多個Dao呼叫。還負責SqlSession的的生命週期,包括關閉,提交和回滾操作
  • SqlSessionTemplate被設計用於替換預設的DefaultSqlSession

6. 注入對映器

  • 為了代替手工呼叫SqlSessionTemplate編寫DAO層業務程式碼,mybatis-spring提供了動態代理的實現類:MapperFactoryBean,該類是設計成泛型,將mapper介面類自動注入到service類中,無需自己寫實現類,內部會自動建立代理
<
bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<
property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
<
property name="sqlSessionFactory" ref="sqlSessionFactory" />
<
/bean>
複製程式碼
  • MapperFactoryBean建立的代理類實現了UserMapper介面,並注入到應用程式中
  • 為了代替手工註冊每個對映器,可以使用MapperScannerConfigurer,它會建立路徑下所有對映器,被自動建立MapperFactoryBean
<
bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<
property name="basePackage" value="org.mybatis.spring.sample.mapper" />
<
/bean>
複製程式碼

四. Mybatis Springboot Starter

1. 概述

  • 基於springboot快速構建mybatis應用程式
  • 使用mybatis-spring,我們需要在xml中配置SqlSessionFactory和mapper對映介面
  • 使用mybatis-springboot-starter,會自動檢測dataSource,並根據資料來源,使用SqlSessionFactoryBean自動建立並註冊一個SqlSessionFactory,同時將建立SqlSessionTemplate,自動掃描mapper,關聯到SqlSessionTemplate並注入到容器中
  • 預設掃描所有帶@Mapper的介面,自定義掃描某些包,需要使用@MapperSacn註解

2. 如何使用

  • pom中新增mybatis-spring-boot-starter依賴
  • application.xml中新增資料來源和mybatis相關配置資訊
  • 對映介面上新增@Mapper註解,或使用@MapperScan掃描整個包的mapper
  • 業務程式碼中獲取自動注入到容器的mapper介面,呼叫mapper的增刪改查方法運算元據庫

3. 配置檔案

  • 配置資訊放在application.properties或application.yml檔案中,以mybatis作為配置的字首。引數配置同前面介紹的原生mybatis配置
# application.properties# 指定mybatis-config.xml檔案的位置mybatis.config-location=classpath:mybatis-config.xml# 指定mapper的xml檔案路徑mybatis.mapper-locations=classpath:com/xxmybatis.executor-type=SIMPLE# 指定別名的包,多個用逗號分開mybatis.type-aliases-package=com.example.domain.modelmybatis.type-handlers-package=com.example.typehandlermybatis.configuration.map-underscore-to-camel-case=truemybatis.configuration.default-fetch-size=100mybatis.configuration.default-statement-timeout=30複製程式碼

五. Mybatis原始碼分析

1. mybatis相關jar包說明

1.1 mybatis-spring-boot-starter.jar

mybatis原理,配置介紹及原始碼分析
  • 只有一個pom檔案和spring.provides檔案,官方提供的一些starter格式大致都是這個套路。真正處理自動配置功能的是XXX-autoconfigure.jar完成
  • pom中依賴項:jdbc, mybatis, mybatis-spring, mybatis-spring-boot-autoconfigure(真正完成自動配置的jar包)
  • provides:說明這個starter配置以後,自動引入的包有哪些

1.2 mybatis-spring-boot-autoconfigure.jar

mybatis原理,配置介紹及原始碼分析
  • xxx-autoconfigure是開發一個starter預設使用的自動配置包
  • META-INF/spring.factories: 指定了自動配置的類名是MybatisAutoConfiguration
  • MybatisProperties: 指明瞭application.properties檔案中配置資訊對應的屬性類
  • MybatisAutoConfiguration:自動配置實現類,函式入口的地方。根據DataSource自動注入SqlSessionFactory,再根據SqlSessionFactory自動注入SqlSessionTemplate。SqlSessionTemplate內部的操作都是通過建立SqlSession的代理sqlSessionProxy來操作的

1.3 mybatis-spring.jar

mybatis原理,配置介紹及原始碼分析
  • mybatis和spring的整合包

1.4 mybatis.jar

mybatis原理,配置介紹及原始碼分析
  • 最原生的mybatis包

2. 配置檔案載入

2.1 UML圖

mybatis原理,配置介紹及原始碼分析
  • 訪問資料庫層,最基本的介面是SqlSession,它的預設實現為DefaultSqlSession, 在mybatis-spring中使用SqlSessionTemplate
  • SqlSession通過SqlSessionFactory工廠來建立,而sqlSessionFactory通過建造者SqlSessionFactoryBuilder建立
  • SqlSessionFactoryBuilder是通用的構造類類,通過它構造出SqlSessionFactory。可以手工直接呼叫SqlSessionFactoryBuilder。
  • mybatis為了和spring整合,提供了mybatis-spring這個jar包。提供的SqlSessionFactoryBean類,內部封裝了對SqlSessionFactoryBuilder的呼叫
  • springboot進一步提供了MybatisAutoConfiguration做自動配置,內部的sqlSessionFactory方法,最終呼叫了SqlSessionFactoryBean
  • Configuration提供兩類資料,一類是輸入類:Environment,通過給定的配置檔案,將配置資訊

2.2 原始碼跟蹤

  • MybatisAutoConfiguration類內部構造了SqlSessionFactoryBean物件

    mybatis原理,配置介紹及原始碼分析
  • SqlSessionFactoryBean實現了FactoryBean介面,所以getBean獲取例項時實際呼叫他的getObject方法。內部呼叫了afterPropertiesSet方法。afterPropertiesSet方法被重寫,內部呼叫buildSqlSessionFactory

    mybatis原理,配置介紹及原始碼分析
  • buildSqlSessionFactory內部建立了XMLConfigBuilder,用於解析mybatis的配置檔案

    mybatis原理,配置介紹及原始碼分析
  • 真正解析配置檔案的地方

    mybatis原理,配置介紹及原始碼分析
  • 解析的配置檔案的根為configuration,然後依次解析子標籤:包括最重要的mappers標籤。這部分的解析和前面介紹的配置檔案說明是一一對應的,所有標籤都有對應的解析標籤的程式碼

    mybatis原理,配置介紹及原始碼分析
  • 對mapper檔案的解析,內部又具體呼叫了XMLMapperBuilder類的parse方法。這部分的解析與前面介紹的mapper配置檔案說明也是一一對應的

    mybatis原理,配置介紹及原始碼分析
  • 解析mapper檔案時,從根元素mapper開始,包括子節點cache,parameterMap,resultMap,select等。然後將解析的資訊都儲存到Configuration物件中。

    mybatis原理,配置介紹及原始碼分析
  • 其中select,insert,delete,update語句的解析方法為

    mybatis原理,配置介紹及原始碼分析
  • 解析完之後,放入一個map中,每條sql語句對應一個MappedStatement物件。其他屬性的解析類似,大多是放到map中。

    mybatis原理,配置介紹及原始碼分析
    mybatis原理,配置介紹及原始碼分析
  • 解析完所有的配置檔案,得到Configuration物件,將它作為引數傳給SqlSessionFactoryBuilder的build方法

    mybatis原理,配置介紹及原始碼分析
  • SqlSessionFactoryBuilder內部根據Configuration引數,建立DefaultSqlSessionFactory類

    mybatis原理,配置介紹及原始碼分析
  • DefaultSqlSessionFactory建構函式只是將Configuration儲存了下來,當需要獲取session時,根據內部的configuration去具體建立

    mybatis原理,配置介紹及原始碼分析
  • 得到SqlSessionFactory後,根據它去建立SqlSessionTemplate

    mybatis原理,配置介紹及原始碼分析
  • SqlSessionTemplate內部建立SqlSession的代理類,將沒有加事務的SqlSession的操作做強制提交

    mybatis原理,配置介紹及原始碼分析
    mybatis原理,配置介紹及原始碼分析

3. 動態代理的實現

3.1 概述

Dao層都是是一些介面 它並沒有實現類,為什麼介面可以直接使用呢? 那是因為MyBbatis使用了JDK動態代理機制動態生成了代理類,那麼代理類又是如何對SqlSession進行封裝的呢?

3.2 UML圖

mybatis原理,配置介紹及原始碼分析

3.3 原始碼跟蹤

註冊mapper並建立代理類

  • MapperScanConfiguration這個bean,掃描給定包下所有的mapper檔案,並註冊到MapperRegistry中
    mybatis原理,配置介紹及原始碼分析
  • MapperRegistry中的addMappers方法將包名下每個mapper類建立一個MapperProxyFactory,放入map中。
    mybatis原理,配置介紹及原始碼分析
    mybatis原理,配置介紹及原始碼分析
  • 獲取mapper時,從map中找到對應的MapperProxyFactory,並將sqlSession引數傳給newInstance,建立出代理類
    mybatis原理,配置介紹及原始碼分析
  • 建立代理類呼叫了JDK的動態代理方法,被代理類為DAO介面,代理類為MapperProxy
    mybatis原理,配置介紹及原始碼分析
  • MapperProxy實現了InvocationHandler,重寫invoke方法。該方法主要呼叫MapperMethod的execute方法
    mybatis原理,配置介紹及原始碼分析
  • MapperMethod的建立需要三個引數:DAO介面本身,方法類,Configuration物件
    mybatis原理,配置介紹及原始碼分析
  • MapperMethod內部新建了兩個類:SqlCommand,MethodSignature
    mybatis原理,配置介紹及原始碼分析
  • SqlCommand主要儲存了要查詢的這個介面方法的方法名稱和SQL查詢型別,這兩個值都需要先查詢MappedStatemen
    mybatis原理,配置介紹及原始碼分析
  • MappedStatement查詢就是在前面章節說道瞭解析檔案完成後儲存到的Configuration的map中查詢
    mybatis原理,配置介紹及原始碼分析
  • MethodSignature主要儲存引數,返回值,返回型別等資訊,主要解析Method類
    mybatis原理,配置介紹及原始碼分析
  • MapperMethod執行execute時,就是根據前面建立的SqlCommand和MethodSignature的一些屬性執行不同的操作,這些操作都呼叫了SqlSession介面。比如:xml中的select語句,SqlCommand中type指定為SELECT,execute根據不同type執行不同方法。xml中返回型別是單條記錄,還是多條記錄。分別對應MethodSignature的不同屬性,然後執行不同的方法。
    mybatis原理,配置介紹及原始碼分析

獲取mapper並執行

  • mapper的註冊前面介紹了是通過MapperRegistry的addMappers方法,而獲取mapper的方法是getMapper,那麼誰來呼叫這個getMapper方法呢?
  • 當我們再service中使用@Autowired註解獲取某個mapper介面時,實際上是呼叫了spring為我們自動注入的bean,這個操作是由MapperFactoryBean泛型類來完成。同SqlSessionFactoryBean一樣,MapperFactoryBean實現了FactoryBean介面,所以getBean獲取例項時實際呼叫他的getObject方法。getObejct內部通過sqlSession呼叫getMapper方法,避免了原生mybatis中每次手動通過sqlSession呼叫getMapper方法。
    mybatis原理,配置介紹及原始碼分析
  • session物件是MapperFactoryBean的父類SqlSessionDaoSupport的屬性,內部具體實現類是SqlSessionTemplate
    mybatis原理,配置介紹及原始碼分析
  • SqlSessionTemplate的getMapper方法,實際呼叫的是Configuration的getMapper方法
    mybatis原理,配置介紹及原始碼分析
  • Configuration中的getMapper方法呼叫的就是前面一小節介紹的MapperRegistry類中註冊進去所有進行了動態代理後,放入一個map的物件
    mybatis原理,配置介紹及原始碼分析

六. Mybatis Generator

1. 概述

  • mybatis generator是一個mybatis程式碼自動生成工具。官方文件中文文件
  • 生成的內容包括:
    • 實體物件:指定資料庫中指定表對應的java實體類
    • mapper xml檔案:每張表對應的增刪改查SQL語句
    • DAO介面:和SQL語句對應的java查詢介面
  • 多次生成時注意的事項:
    • xml檔案會自動合併,不會覆蓋已有的內容
    • java檔案不會合並,它預設會生成一個不同名字的檔案。可通過引數配置覆蓋原有的檔案

2. 如何使用

2.1 命令列執行使用

  • 定義配置檔案
  • 執行以下命令
 java -jar mybatis-generator-core-x.x.x.jar -configfile \temp\generatorConfig.xml -overwrite複製程式碼

2.2 spring或springboot中使用

  • pom中新增依賴
    <
    build>
    <
    plugins>
    <
    plugin>
    <
    groupId>
    org.mybatis.generator<
    /groupId>
    <
    artifactId>
    mybatis-generator-maven-plugin<
    /artifactId>
    <
    version>
    ${mybatis-generator.version
    }<
    /version>
    <
    configuration>
    <
    overwrite>
    true<
    /overwrite>
    <
    verbose>
    true<
    /verbose>
    <
    /configuration>
    <
    dependencies>
    <
    dependency>
    <
    groupId>
    mysql<
    /groupId>
    <
    artifactId>
    mysql-connector-java<
    /artifactId>
    <
    version>
    ${mysql.version
    }<
    /version>
    <
    /dependency>
    <
    /dependencies>
    <
    /plugin>
    <
    /plugins>
    <
    /build>
    複製程式碼
  • 執行外掛
    mybatis原理,配置介紹及原始碼分析

3. 配置檔案說明

    <
?
xml version="1.0" encoding="UTF-8"?>
<
!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<
generatorConfiguration>
<
!--非必填選項,用於新增執行類路徑位置到類路徑中-->
<
classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />
<
!--元素用於指定生成一組物件的環境-->
<
context id="DB2Tables" targetRuntime="MyBatis3">
<
!--註釋生成器的屬性-->
<
commentGenerator>
<
property name="suppressDate" value="true" />
<
!-- 是否去除自動生成的註釋 true:是 : false:否 -->
<
property name="suppressAllComments" value="true"/>
<
/commentGenerator>
<
!--指定資料庫連線資訊-->
<
jdbcConnection driverClass="COM.ibm.db2.jdbc.app.DB2Driver" connectionURL="jdbc:db2:TEST" userId="db2admin" password="db2admin">
<
/jdbcConnection>
<
!--用於定義Java型別解析器的屬性-->
<
javaTypeResolver >
<
property name="forceBigDecimals" value="false" />
<
/javaTypeResolver>
<
!-- 生成實體類的包名和位置-->
<
javaModelGenerator targetPackage="test.model" targetProject="\MBGTestProject\src">
<
property name="enableSubPackages" value="true" />
<
property name="trimStrings" value="true" />
<
/javaModelGenerator>
<
!-- 生成mapper xml檔案的包名和位置-->
<
sqlMapGenerator targetPackage="test.xml" targetProject="\MBGTestProject\src">
<
property name="enableSubPackages" value="true" />
<
/sqlMapGenerator>
<
!-- 生成DAO的包名和位置-->
<
javaClientGenerator type="XMLMAPPER" targetPackage="test.dao" targetPackage="xx" targetProject="\MBGTestProject\src">
<
property name="enableSubPackages" value="true" />
<
/javaClientGenerator>
<
!--指定生成哪個表的資訊-->
<
table schema="DB2ADMIN" tableName="ALLTYPES" domainObjectName="Customer" >
<
property name="useActualColumnNames" value="true"/>
<
!--指定自動生成的主鍵-->
<
generatedKey column="ID" sqlStatement="DB2" identity="true" />
<
columnOverride column="DATE_FIELD" property="startDate" />
<
ignoreColumn column="FRED" />
<
!--自定義列資訊,覆蓋預設資訊,包括property,javaType,jdbcType,typeHandler,delimitedColumnName屬性-->
<
columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />
<
/table>
<
/context>
<
/generatorConfiguration>
複製程式碼

七. PageHelper

1. 概述

2. 如何使用

  • 新增springboot依賴
    <
    dependency>
    <
    groupId>
    com.github.pagehelper<
    /groupId>
    <
    artifactId>
    pagehelper-spring-boot-starter<
    /artifactId>
    <
    version>
    ${pageHelper.version
    }<
    /version>
    <
    /dependency>
    複製程式碼
  • 在application.properties中新增配置說明
    # 分頁外掛會自動檢測當前的資料庫連結,自動選擇合適的分頁方式。 你可以配置helperDialect屬性來指定分頁外掛使用哪種方言pagehelper.helperDialect=mysql# 分頁合理化引數,預設值為false。當該引數設定為 true 時,pageNum<
    =0 時會查詢第一頁,
    # pageNum>
    pages(超過總數時),會查詢最後一頁。預設false 時,直接根據引數進行查詢。
    pagehelper.reasonable=true# 預設值為false,該引數對使用 RowBounds 作為分頁引數時有效。 當該引數設定為true時,使用 RowBounds 分頁會進行 count 查詢。pagehelper.row-bounds-with-count=false# 為了支援startPage(Object params)方法,增加了該引數來配置引數對映,用於從物件中根據屬性名取值# 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置對映的用預設值# 預設值為pageNum=pageNum;
    pageSize=pageSize;
    count=countSql;
    reasonable=reasonable;
    pageSizeZero=pageSizeZero
    pagehelper.params=# 支援通過 Mapper 介面引數來傳遞分頁引數,預設值false,分頁外掛會從查詢方法的引數值中,# 自動根據上面 params 配置的欄位中取值,查詢到合適的值時就會自動分頁pagehelper.supportMethodsArguments=false# 預設值為 false,當該引數設定為 true 時,如果 pageSize=0 或者 RowBounds.limit = 0 # 就會查詢出全部的結果(相當於沒有執行分頁查詢,但是返回結果仍然是 Page 型別)pagehelper.pageSizeZero=false# autoRuntimeDialect:預設值為 false。設定為 true 時,允許在執行時根據多資料來源自動識別對應方言的分頁 # pring 中配置了動態資料來源,並且連線不同型別的資料庫,這時你可以配置為truepagehelper.autoRuntimeDialect: false# 預設值為 true。當使用執行時動態資料來源或沒有設定 helperDialect 屬性自動獲取資料庫型別時,會自動獲取一個資料庫連線,# 通過該屬性來設定是否關閉獲取的這個連線,預設true關閉,設定為 false 後,不會關閉獲取的連線# 這個引數的設定要根據自己選擇的資料來源來決定pagehelper.close-conn=false複製程式碼
  • 在程式碼中呼叫
    //方法一:Mapper介面方式的呼叫,startPage,推薦這種使用方式。PageHelper.startPage(1, 10);
    List<
    Country>
    list = countryMapper.selectIf(1);
    //方法二:Mapper介面方式的呼叫,offsetPage, 推薦這種使用方式。PageHelper.offsetPage(1, 10);
    List<
    Country>
    list = countryMapper.selectIf(1);
    //方法三:引數方法呼叫//存在以下 Mapper 介面方法,你不需要在 xml 處理後兩個引數public interface CountryMapper {List<
    Country>
    selectByPageNumSize( @Param("user") User user, @Param("pageNum") int pageNum, @Param("pageSize") int pageSize)
    ;

    }//配置supportMethodsArguments=true//在程式碼中直接呼叫:List<
    Country>
    list = countryMapper.selectByPageNumSize(user, 1, 10);
    //方法四:java8 lambda呼叫//jdk8 lambda用法Page<
    Country>
    page = PageHelper.startPage(1, 10).doSelectPage(()->
    countryMapper.selectGroupBy());
    pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() ->
    countryMapper.selectGroupBy());
    //count查詢,返回一個查詢語句的count數total = PageHelper.count(()->
    countryMapper.selectLike(country));
    複製程式碼

3. 使用注意

  • PageHelper.startPage使用靜態的ThreadLocal的,分頁和執行緒繫結,使用startPage時,後面必須緊跟著dao查詢,分頁才能生效

來源:https://juejin.im/post/5bd02b3d6fb9a05cee1e2478

相關文章