1. 程式人生 > >mybatis3.4.6 原始碼分析

mybatis3.4.6 原始碼分析

ORM(來自baidu): 物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程式技術,用於實現面向物件程式語言裡不同型別系統的資料之間的轉換

自我梳理了一下mybatis,歡迎大神批評指正,交流學習,感謝!

常用使用說明

  1. 使用mybatis整合pom配置 使用我的練習專案;第一次自己搭maven 在這裡插入圖片描述 可以在一個maven工程裡放子工程,這個方式還挺好的;兩個子專案可以共用父專案的pom配置


	<dependencies>
		<!-- mysql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.13</version>
		</dependency>
		
		<!-- mybatis -->
		<dependency>
		  <groupId>org.mybatis</groupId>
		  <artifactId>mybatis</artifactId>
		  <version>3.4.6</version>
		</dependency>
		
		<!-- log4j -->
		<dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        
        <!-- mybatis會用到 start -->
        <dependency>
		    <groupId>org.javassist</groupId>
		    <artifactId>javassist</artifactId>
		    <version>3.21.0-GA</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/ognl/ognl -->
		<dependency>
		    <groupId>ognl</groupId>
		    <artifactId>ognl</artifactId>
		    <version>2.7.3</version>
		</dependency>
		<!-- mybatis會用到 end -->
		
		<!-- mybatis 分頁外掛 -->
		<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
		<dependency>
		    <groupId>com.github.pagehelper</groupId>
		    <artifactId>pagehelper</artifactId>
		    <version>5.1.7</version>
		</dependency>
		
	</dependencies>
  1. 使用generator外掛使用 pom配置
  <build>
  	<plugins>
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.7</version>
             <configuration>
             	<!--允許移動生成的檔案-->
                <verbose>true</verbose>
                <!--允許覆蓋生成的檔案-->
                <overwrite>true</overwrite>
                <configurationFile>src/main/resources/config/generatorConfig.xml</configurationFile>
            </configuration>
        </plugin>
    </plugins>
  </build>

generator.xml配置

<?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>
   
    
        <!-- 引入配置檔案   
    <properties resource="jdbc.properties"/>  -->
    
         <!--資料庫驅動路徑-->
      <classPathEntry location="D:\TSBrowserDownloads\maven\mavenSource\mysql\mysql-connector-java\8.0.13\mysql-connector-java-8.0.13.jar" />
    <context id="DB2Tables" targetRuntime="MyBatis3">
      <commentGenerator>
        <property name="suppressAllComments" value="true"/><!-- 是否取消註釋 -->  
        <property name="suppressDate" value="true" /> <!-- 是否生成註釋代時間戳-->
      </commentGenerator>
      <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/zhaowd?serverTimezone=GMT"
            userId="root" password="12345">
        </jdbcConnection>
        <!-- 型別轉換 -->
      <javaTypeResolver>
      <!-- 是否使用bigDecimal, false可自動轉化以下型別(Long, Integer, Short, etc.) --> 
         <property name="forceBigDecimals" value="false"/>
      </javaTypeResolver>
      <!-- 生成實體類的包名和位置 注意targetProject的值為實體類放在工程中具體位置的相對路徑,-->  
      <javaModelGenerator targetPackage="zhaowd.source" targetProject="src/main/java">
      <!-- 是否在當前路徑下新加一層schema,eg:fase路徑com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
          <property name="enableSubPackages" value="true"/>
           <!-- 是否針對string型別的欄位在set的時候進行trim呼叫 -->  
          <property name="trimStrings" value="true"/>
      </javaModelGenerator>
       <!--XML對映檔案,生成的位置(目標包),原始碼資料夾-->
      <sqlMapGenerator targetPackage="sqlmap" targetProject="src/main/resources">
           <property name="enableSubPackages" value="true"/>
      </sqlMapGenerator>
       <!--XML對應的Mapper類-->
      <javaClientGenerator type="XMLMAPPER" targetPackage="zhaowd.mapper" targetProject="src/main/java">
        <property name="enableSubPackages" value="true"/>
      </javaClientGenerator>
      
         <!--下面是資料庫表名和專案中需要生成類的名稱,建議和資料庫保持一致,如果有多個表,新增多個節點即可   enable*ByExample   
                是否生成 example類-->
      <table schema="zhaowd" tableName="user_info" domainObjectName="UserInfo" enableCountByExample="false" enableSelectByExample="true" enableUpdateByExample="false" enableDeleteByExample="false">
       
      </table>
    </context>
      
    </generatorConfiguration>

使用方法:右鍵專案–>run as–>maven Build 自動生成mybatis需要的內容,mapper介面,mapper.xml,表實體 預設直接覆蓋原有的,所以儘量不要在生成的檔案中編寫自己的程式碼,使用單獨的檔案,防止覆蓋

  1. 分頁 mybatis自帶方法裡的分頁引數是對結果集進行分頁的,就是假分頁 方法1:就是使用sql語句的拼裝去分頁,直接使用資料庫的sql 方法2:使用分頁外掛,比如pagehelper
    • pom配置見上面mybatis的配置
    • 使用說明:再查詢之前增加PageHelper.startPage(當前頁,限制數量);即可
    • 注意事項見圖片程式碼註釋 在這裡插入圖片描述

使用過程中的異常

  1. Caused by: java.lang.IllegalStateException: Cannot enable lazy loading because Javassist is not available. Add Javassist to your classpath.
Caused by: java.lang.IllegalStateException: Cannot enable lazy loading because Javassist is not available. Add Javassist to your classpath.
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.<init>(JavassistProxyFactory.java:55)
	at org.apache.ibatis.session.Configuration.<init>(Configuration.java:131)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.<init>(XMLConfigBuilder.java:86)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.<init>(XMLConfigBuilder.java:82)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:77)
	... 25 more
Caused by: java.lang.ClassNotFoundException: Cannot find class: javassist.util.proxy.ProxyFactory

缺少jar依賴

        <dependency>
		    <groupId>org.javassist</groupId>
		    <artifactId>javassist</artifactId>
		    <version>3.21.0-GA</version>
		</dependency>
  1. Caused by: java.lang.RuntimeException: MemberAccess implementation must be provided! ognl版本不對,可能太高了
修改成:
		<dependency>
		    <groupId>ognl</groupId>
		    <artifactId>ognl</artifactId>
		    <version>2.7.3</version>
		</dependency>

原始碼分析

程式呼叫鏈條如下圖所示:

1.流程呼叫圖(簡化版) 在這裡插入圖片描述

2.複雜點的(這有點亂,結合簡化版的看) 在這裡插入圖片描述

  1. 目錄結構說明 annotations:註解定義 binding:繫結mapper介面與mapper.xml的關係 builder:註解+配置解析 cache:快取 cursor: datasource:資料來源 exceptions:異常 executor:sql的實際執行者 io:讀檔案 jdbc:底層相關 lang: logging:日誌 mappering:對映到實體 parsing:解析配置+註解 plugin:外掛,攔截器 reflection:反射 scripting:引數處理 session:session transaction: type:型別

原始碼

原始碼的呼叫流程見上圖

學習:

  1. Configuration 目前mybatis支援兩種方式的實現功能
    • 程式設計式:只是單純的使用mybaits去作為持久化層去使用,mybatis提供xml的形式去簡化配置
    • 整合式:比如整合在spring中使用,可以使用Configuration去設定配置引數 程式設計式在使用過程中,也會將xml對映到Configuration上 Configuration與SqlSessionFactory一一對應
  2. 快取
    1. 一級快取:預設開啟,session級別的,第一查詢進行快取,第二次查詢從快取裡取

      • 如果同一個sesssion,在兩次查詢之間有更新資料的操作(update,delete)並提交,session的所有快取都會清
      • 如果有不同的session,在兩次查詢之間有更新資料的操作(update,delete),第二次查詢的資料就是髒資料了,session之間快取都是獨立的 一級快取是在取二級快取之後(如果二級開關開啟的話) 在這裡插入圖片描述

      設定一級快取的時候會使用一個佔位符去佔位,作用:比如在聯合查詢中,第二個sql在執行時,可能會命中第二個sql在單獨執行時的一級快取,如果獲取到快取的值是這個佔位符,表示這個快取不能使用;應該就是這個聯合查詢的第二個sql不載入到快取裡,由正在處理的加

      在這裡插入圖片描述

    2. 二級快取:預設關閉,一般使用第三方實現(redies),nameSpace級別的,共享給所有的sqlSession

      • 同一個namespace下的upd,del會清掉該space下的快取同一個namespace下的upd,del會清掉該space下的快取
      • 如果是關聯查詢,快取也只是當前namespace下的;如果另外一個namespace對資料有更新,不會影響其他namespace下的快取,哪怕是關聯查詢的第二條sql 在這裡插入圖片描述

在這裡插入圖片描述

  1. plugin機制 攔截

  2. ObjectFactory 建立結果物件的例項

    • 拿到結果集,建立結果對映物件,就是實體物件(通過反射呼叫無參構造,如有自定義objectFactory,呼叫create建立)之後;這個時候還沒有對映
    • 入參設定同理
  3. laze Loading機制 * 在這裡插入圖片描述

    • 如果lazyLoading開啟,預設是javassist,可選cglib/自定義;會通過config去建立一個proxyFactory(java、cglib)的代理的代理物件 位置:org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(ResultSetWrapper, ResultMap, ResultLoaderMap, String)
  4. 異常機制

  5. log

問題: