1. 程式人生 > >MyBatis原始碼分析(一)

MyBatis原始碼分析(一)

MyBatis故事:

  官方網站:http://www.mybatis.org

  官方文件:http://www.mybatis.org/mybatis-3/ 

  GitHub:https://github.com/mybatis

通過在MyBatis的官方網站,我們會看到和MyBatis相關的一些軟體產品:

  MyBatis Migrations 是一款資料庫遷移工具 http://www.mybatis.org/migrations;

  MyBatipse (Eclipse plugin) ,Eclipse外掛提供在編寫xml配置檔案時的內容提示和驗證;

  MyBatis Generator 程式碼生成工具;

What is MyBatis?

MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates almost all of the JDBC code and manual setting of parameters and retrieval of results. MyBatis can use simple XML or Annotations for configuration and map primitives, Map interfaces and Java POJOs (Plain Old Java Objects) to database records.

MyBatis 是一款優秀的持久層框架,它支援自定義 SQL、儲存過程以及高階對映。MyBatis 免除了幾乎所有的 JDBC 程式碼以及設定引數和獲取結果集的工作。MyBatis 可以通過簡單的 XML 或註解來配置和對映原始型別、介面和 Java POJO(Plain Old Java Objects,普通老式 Java 物件)為資料庫中的記錄。

MyBatis SQL mapper framework for Java可以將其稱之為Java持久層框架.

MyBatis 的前身是apache下的一個開源專案iBatis,  iBATIS是一個由Clinton Begin在2002年發起的開源專案,是一個基於Java的持久層框架。

iBATIS:http://ibatis.apache.org

iBATIS這個專案於2010年6月16號由apache遷移到了google code,iBatis3.x並且改名為MyBatis 。

MyBatis: http://code.google.com/p/mybatis/ (現在已經無法開啟)

2013年11月MyBatis又從google code將程式碼遷移到Github。

MyBatis和Hibernate

MyBatis的作者:Clinton Begin 加拿大人  https://www.linkedin.com/in/clintonbegin 

Hibernate 2001年推出的Java持久層框架,澳大利亞人 Gavin King  https://www.linkedin.com/in/GavinKing 

人們經常喜歡比較這兩款優秀的持久層框架的特點:

技術 優點 缺點
jdbc 簡單,純粹,一切均可見,最基礎的一種技術

1:需要手動關閉連線

2:結果集不能自動對映為物件

3:SQL夾雜在程式碼中,耦合度高,導致硬編碼內傷

4:實際開發中SQL經常隨需求變動,導致頻繁修改,不易維護

jdbcTemplate

簡單、純粹、自動會話管理、結果集對映

需要手動拼裝SQL,SQL與Java程式碼混合在一起,長的SQL管理混亂

Hibernate

JPA

程式設計效率高,無需編寫SQL。
資料庫更換成本低

較完善的二級快取、自動防SQL注入

完全掌握的門檻高;
複雜SQL、複雜對映處理困難;
效能優化較麻煩、不易做特殊優化;
基於全對映的全自動框架,大量欄位的POJO進行部分對映時比較困難,導致資料庫效能下降;

MyBatis

學習成本低、可以進行更為細膩的SQL優化,減少查詢欄位、統一的SQL管理
SQL和Java編碼分開,功能邊界清晰

需要手動編寫維護SQL、表結構變更之後需要手動維護SQL與對映;

 MyBatis的定位

MyBatis專注於SQL本身,其為SQL對映,而非完整的SQL對映,它是一個半自動的ORM框架,需要自己編寫SQL語句,這是其優點,也是缺點.

優點:SQL語句單獨維護,便於SQL優化,便於發揮SQL的最大效能.

缺點:當資料庫表和欄位更改後,實體和資料庫的對映關係需要手動維護,耗費時間長.

使用場景:是用於效能要求高,有大量的查詢操作,適用於網際網路專案,如:電商,O2O

網際網路專案對持久層的需求:

1:對資料庫的訪問更加純粹

2:儘可能不要使用資料庫做運算

3:SQL語句儘可能命中索引(欄位排序,查詢欄位,查詢條件,儘可能命中索引)

MyBatis實戰應用:

  Mybatis框架就一個jar包;要使用 MyBatis, 只需將 mybatis-3.5.1.jar 檔案置於 classpath 中即可。

  使用Maven構建專案

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.1</version>
</dependency>

下載MyBatis原始碼,構建MyBatis專案;https://codeload.github.com/mybatis/mybatis-3/zip/mybatis-3.5.1

如果不出意外,我們解壓下載的壓縮包,然後通過pom.xml匯入IDEA中,通過Maven的compiler就可以正常編譯成功,首次編譯可能需要一定時間。

為了驗證我麼編譯的專案是否可用,我們可以寫一個簡單的案例專案去測試一下,也方便後續的斷點跟蹤原始碼分析。

建立普通的Maven專案,新增Maven依賴

 

 <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!--mysql的jdbc驅動jar包依賴-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!--lombok程式碼生成工具的jar包依賴-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>

        <!--slf4j日誌門面-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>

        <!--log4j2日誌實現-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.11.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.11.2</version>
        </dependency>

        <!-- cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

        <!-- javassist -->
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.27.0-GA</version>
        </dependency>

 

新增resources編譯,個人建議新增

  <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>

新增jdbc.properties,根據自身配置

jdbc.username=xxx
jdbc.password=xxxxx
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://xxxx:3306/xxx?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false

最後貼上mybatis的xml配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--dtd的xml約束是有順序,標籤順序不能錯-->
<configuration>

    <!--mybatis框架的核心功能可以通過該配置進行設定-->

    <!--配置屬性-->
    <properties resource="D:\mybatis-3-mybatis-3.5.1\mybatis3-test\src\main\resources\jdbc.properties"/>

    <settings>
        <!--mybatis輸出日誌,採用何種元件輸出-->
        <setting name="logImpl" value="SLF4J"/>
        <!--開啟二級快取-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <!--類型別名-->
    <typeAliases>
        <typeAlias type="com.xxx.model.User" alias="User"/>
    </typeAliases>

    <typeHandlers>
        <!--自定義的型別轉換器-->
        <typeHandler handler="com.xxx.type.CryptHandlerType"
                javaType="com.xxx.model.IdCardType"/>
    </typeHandlers>

    <!--外掛-->
    <!--
    <plugins>
        <plugin interceptor="com.xxx.plugin.xxxx"></plugin>
    </plugins>
    -->

    <!--多環境配置,預設開發-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

        <environment id="product">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--對映器-->
    <mappers>
      
        <mapper resource="com/bjpowernode/mapper/UsersMapper.xml"/>
    </mappers>

</configuration>

日誌配置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug">

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

貼上本人的專案結構,僅供參考

 

MyBatis獨立使用  

     //通過配置檔案獲取輸入流
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");

        //構建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //開啟session
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //第四步 獲取Mapper介面物件
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //第五步 呼叫Mapper介面物件的方法操作資料庫
        User user = mapper.selectByPrimaryKey(1);

        //獲取結果,處理業務
        log.info("查詢結果:",user.getId());

 

當我們資料庫配置等都設定完畢,正常來說查詢資料是不會出現異常的,這樣就說明我們的原始碼編譯是成功的。

MyBatis Generator (MBG)

 

 

MyBatis Generator 簡稱MBG,是用Java語言開發的一個程式碼生成工具,可以深入分析你的資料庫和表,幫助你生成基本的對資料庫的CRUD操作程式碼以及QBC風格的條件查詢,但是表連線、儲存過程等這些複雜SQL的定義需要我們手工編寫。

 

MyBatis Generator 生成3個東西:

1、POJO

2、Mapper XML Files

3、Mapper interface

MyBatis Generator 生成程式碼不需要依賴任何第三方jar包,僅僅需要一個jdbc驅動包;

文件:http://www.mybatis.org/generator/

Github:https://github.com/mybatis/generator

原來MyBatis Generator老版本:ibator,用於iBatis程式碼生成;

1、配置MyBatis Generator (MBG) 的配置檔案;

<?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"/>

    <!-- 指定連線資料庫的JDBC驅動包所在位置,指定到你本機的完整路徑 -->
    <classPathEntry location="F:/mysql-connector-java-5.1.46.jar"/>

    <!-- 配置table表資訊內容體,targetRuntime指定採用MyBatis3的版本 -->
    <context id="tables" targetRuntime="MyBatis3">

        <!-- 抑制生成註釋,由於生成的註釋都是英文的,可以不讓它生成 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!-- 配置資料庫連線資訊 -->
        <connectionFactory>
            <property name="driverClass" value="${jdbc.driver}"/>
            <property name="connectionURL" value="${jdbc.url}"/>
            <property name="userId" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </connectionFactory>

        <!-- 配置資料庫連線資訊 connectionFactory與jdbcConnection只能配置其一-->
        <!--
        <jdbcConnection driverClass="COM.ibm.db2.jdbc.app.DB2Driver"
                        connectionURL="jdbc:db2:TEST"
                        userId="db2admin"
                        password="db2admin">
        </jdbcConnection>
        -->

        <!-- 生成model類,targetPackage指定model類的包名, targetProject指定生成的model放在eclipse的哪個工程下面-->
        <javaModelGenerator targetPackage="org.mybatis.model" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
            <property name="trimStrings" value="false" />
        </javaModelGenerator>

        <!-- 生成MyBatis的Mapper.xml檔案,targetPackage指定mapper.xml檔案的包名, targetProject指定生成的mapper.xml放在eclipse的哪個工程下面 -->
        <sqlMapGenerator targetPackage="org.mybatis.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>

        <!-- 生成MyBatis的Mapper介面類檔案,targetPackage指定Mapper介面類的包名, targetProject指定生成的Mapper介面放在eclipse的哪個工程下面 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="org.mybatis.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <!-- 資料庫表名及對應的Java模型類名 -->
        <table tableName="user"
                domainObjectName="User"
                enableCountByExample="false"
                enableUpdateByExample="false"
                enableDeleteByExample="false"
                enableSelectByExample="false"
                selectByExampleQueryId="false"/>
    </context>

</generatorConfiguration>

1、生成程式碼

   --通過命令列生成 java -jar mybatis-generator-core-1.3.7.jar -configfile generatorConfig.xml (用得比較少)

   --通過Ant生成 (ant幾乎被淘汰了)

   --通過java程式生成

   --通過maven生成 

 <plugins>
            <!--mybatis程式碼自動生成外掛-->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.7</version>
                <configuration>
                    <!--配置檔案的位置-->
                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                    <!--生成程式碼過程中是否列印日誌-->
                    <verbose>true</verbose>
                    <!--生成時是否覆蓋java檔案,xml檔案總是合併-->
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>

   --通過Eclipse生成

建議不要用mysql驅動8.0, 用5.1.x系列的驅動;

使用maven外掛通過以下方式即可自動生成。

在原始碼分析的前面,我會分享一些MyBatis的常規應用

&n