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,Serial
SqlSession openSession(TransactionIsolationLevel level)
//查詢型別:simple,batch,reuse
SqlSession 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()

//關閉session
void 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/xx
mybatis.executor-type=SIMPLE
# 指定別名的包,多個用逗號分開
mybatis.type-aliases-package=com.example.domain.model
mybatis.type-handlers-package=com.example.typehandler
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.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 中配置了動態資料來源,並且連線不同型別的資料庫,這時你可以配置為true
    pagehelper.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查詢,分頁才能生效

相關文章