1. 程式人生 > 其它 >MyBatis(一)MyBatis初識

MyBatis(一)MyBatis初識

MyBatis介紹

轉載自:http://c.biancheng.net/mybatis

​ MyBatis 是一款的持久層框架,它支援定製化 SQL、儲存過程以及高階對映。MyBatis 避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和對映原生資訊,將介面和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java物件)對映成資料庫中的記錄。

​ MyBatis 本是apache的一個開源專案iBatis, 2010年這個專案由apache software foundation 遷移到了google code,並且改名為MyBatis 。2013年11月遷移到Github。

mybatis/mybatis-3: MyBatis SQL mapper framework for Java (github.com)

安裝MyBatis

引入依賴

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

當然引入MyBatis之前還需要引入驅動,這裡使用mysql驅動 當前版本 8.0.27

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>x.x.x</version>
</dependency>

在這個地址檢視版本Releases · mybatis/mybatis-3 (github.com)

當前版本是3.5.8

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

sql語句

在開始之前先在資料庫中執行以下內容

CREATE DATABASE IF NOT EXISTS `jdbc_test`;

DROP TABLE IF EXISTS `blog`;
CREATE TABLE `blog` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `blog_title` varchar(20),
  `desc` varchar(300),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

insert into blog(`blog_title`,`desc`) values ("部落格名稱","部落格描述");
insert into blog(`blog_title`,`desc`) values ("部落格名稱1","部落格描述1");

MyBatis核心物件

MyBatis 有三個基本要素:

  • 核心介面和類
  • MyBatis核心配置檔案(mybatis-config.xml)
  • SQL對映檔案(mapper.xml)

下面首先介紹 MyBatis 的核心介面和類,如下所示。

​ 每個 MyBatis 應用程式都以一個 SqlSessionFactory 物件的例項為核心。

​ 首先獲取 SqlSessionFactoryBuilder 物件,可以根據 XML 配置檔案或者 Configuration 類的例項構建該物件。

​ 然後獲取 SqlSessionFactory 物件,該物件例項可以通過 SqlSessionFactoryBuilder 物件來獲取。

​ 有了SqlSessionFactory物件之後,就可以進而獲取SqlSession例項。SqlSession 物件中完全包含以資料庫為背景的所有執行 SQL 操作的方法,用該例項可以直接執行已對映的 SQL 語句。

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder 會根據配置資訊或者程式碼生成 SqlSessionFactory,並且提供了多個 build() 方法過載。

通過原始碼分析,可以發現以上方法都是在呼叫同一簽名方法,即:

build(Reader reader, String environment, Properties properties)

由於引數 environment 和 properties 都可以為 null,去除重複的方法,真正的過載方法其實只有如下三種:

  • build(InputStream inputStream, String environment, Properties properties)
  • build(Reader reader, String environment, Properties properties)
  • build(Configuration config)

​ 通過上述分析,發現配置資訊可以以三種形式提供給 SqlSessionFactoryBuilder build() 方法,分別是 InputStream(位元組流)、Reader(字元流)、Configuration(類)。

​ 由於位元組流和字元流都屬於讀取配置檔案的方式,所以就很容易想到構建一個 SqlSessionFactory 有兩種方式,即:讀取 XML 配置檔案和編寫程式碼。一般習慣為採取 XML 配置檔案的方式來構造 SqlSessionFactory,這樣一方面可以避免硬編碼,另一方面方便日後配置人員修改,避免重複編譯程式碼。

SqlSessionFactoryBuilder的生命週期和作用域

SqlSessionFactoryBuilder 的最大特點就是用過即丟。建立 SqlSessionFactory 物件之後,這個類就不存在了,因此 SqlSessionFactoryBuilder 的最佳範圍就是存在於方法體內,也就是區域性變數。

SqlSessionFactory

SqlSessionFactory 是工廠介面而不是現實類,他的任務就是建立 SqlSession

所有的 MyBatis 應用都以 SqlSessionFactory 例項為中心,SqlSessionFactory 的例項可以通過 SqlSessionFactoryBuilder 物件來獲取。有了它以後,顧名思義,就可以通過 SqlSession 提供的 openSession() 方法來獲取 SqlSession 例項。原始碼如下。

public interface SqlSessionFactory {
    SqlSession openSession();
    SqlSession openSession(boolean autoCommit);
    SqlSession openSession(Connection connection);
    SqlSession openSession(TransactionIsolationLevel level);
    SqlSession openSession(ExecutorType execType);
    SqlSession openSession(ExecutorType execType, boolean autoCommit);
    SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
    SqlSession openSession(ExecutorType execType, Connection connection);
    Configuration getConfiguration();
}

SqlSessionFactory的生命週期和作用域

SqlSessionFactory 物件一旦建立,就會在整個應用程式過程中始終存在。沒有理由去銷燬或再建立它,並且在應用程式執行中也不建議多次建立 SqlSessionFactory。因此 SqlSessionFactory 的最佳作用域是 Application,即隨著應用程式的生命週期一直存在。這種“存在於整個應用執行期間,並且只存在一個物件例項”的模式就是所謂的單例模式(指在執行期間有且僅有一個例項)。

SqlSession

SqlSession 是用於執行持久化操作的物件,類似於 JDBC 中的 Connection。它提供了面向資料庫執行 SQL 命令所需的所有方法,可以通過 SqlSession 例項直接執行已對映的 SQL 語句。

void clearCache();
Configuration getConfiguration();
void rollback(boolean force);
void commit(boolean force);
int delete(String statement, Object parameter);
...

SqlSession 的用途主要有兩種。

  1. 獲取對映器。讓對映器通過名稱空間和方法名稱找到對應的 SQL,併發送給資料庫,執行後返回結果。
  2. 直接通過“名稱空間(namespace)+SQL id”的方式執行 SQL,不需要獲取對映器。這是 iBatis 版本留下的方式。

SqlSession生命週期和作用域

SqlSession 對應一次資料庫會話。由於資料庫會話不是永久的,因此 SqlSession 的生命週期也不是永久的,每次訪問資料庫時都需要建立 SqlSession 物件。

需要注意的是:每個執行緒都有自己的 SqlSession 例項,SqlSession 例項不能被共享,也不是執行緒安全的。因此 SqlSession 的作用域範圍是 request 作用域或方法體作用域內。

MyBatis配置檔案(mybatis-config.xml)

MyBatis 配置檔案的結構如下。

<?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">
<configuration><!-- 配置 -->
    <properties /><!-- 屬性 -->
    <settings /><!-- 設定 -->
    <typeAliases /><!-- 型別命名 -->
    <typeHandlers /><!-- 型別處理器 -->
    <objectFactory /><!-- 物件工廠 -->
    <plugins /><!-- 外掛 -->
    <environments><!-- 配置環境 -->
        <environment><!-- 環境變數 -->
            <transactionManager /><!-- 事務管理器 -->
            <dataSource /><!-- 資料來源 -->
        </environment>
    </environments>
    <databaseIdProvider /><!-- 資料庫廠商標識 -->
    <mappers /><!-- 對映器 -->
</configuration>

mybatis-config.xml 檔案中的元素節點是有一定順序的,節點位置必須按以上位置排序,否則會編譯錯誤。

下面介紹 XML 配置檔案中的重要元素(標籤)。

configuration 元素是整個 XML 配置檔案的根節點,其角色就相當於是 MyBatis 的總管,MyBatis 所有的配置資訊都會存放在它裡面。

properties標籤

properties 標籤可以通過 resource 屬性指定外部 properties 檔案(database.properties),也可以通過 properties 子元素配置。

1. 指定檔案

使用 properties 指定外部檔案,程式碼如下。

<properties resource="mybatisDemo/resources/database.properties"/>

database.properties 用於描述資料庫連線的相關配置,例如資料庫驅動、連線資料庫的 url、資料庫使用者名稱、資料庫密碼等。

2. properties子元素配置

通過 properties 子元素 property 配置 usernamepassword變數,然後在 environments 節點中引用這些變數,程式碼如下。

<properties>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</properties>

在 environments 節點中引用 username 和 password 變數。

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

也可以不使用 properties 標籤,直接將屬性值寫在 value 中。

settings標籤

settings 標籤用於配置 MyBatis 的執行時行為,它能深刻的影響 MyBatis 的底層執行,一般不需要大量配置,大部分情況下使用其預設值即可。

settings 的配置項很多,但是真正用到的不會太多,我們把常用的配置項研究清楚就可以了。settings 配置項說明如下表所示

配置項 作用 配置選項 預設值
cacheEnabled 該配置影響所有對映器中配置快取的全域性開關 true|false true
lazyLoadingEnabled 延遲載入的全域性開關。當開啟時,所有關聯物件都會延遲載入。在特定關聯關係中可通過設定 fetchType 屬性來覆蓋該項的開關狀態 true|false false
aggressiveLazyLoading 當啟用時,對任意延遲屬性的呼叫會使帶有延遲載入屬性的物件完整載入;反之,每種屬性將會按需載入 true|false 版本3.4.1 (不包含) 之前預設值為 true,之後為 false
multipleResultSetsEnabled 是否允許單一語句返回多結果集(需要相容驅動) true|false true
useColumnLabel 使用列標籤代替列名。不同的驅動會有不同的表現,具體可參考相關驅動文件或通過測試這兩種不同的模式來觀察所用驅動的結果 true|false true
useGeneratedKeys 允許JDBC 支援自動生成主鍵,需要驅動相容。如果設定為 true,則這個設定強制使用自動生成主鍵,儘管一些驅動不能相容但仍可正常工作(比如 Derby) true|false false
autoMappingBehavior 指定 MyBatis 應如何自動對映列到欄位或屬性。 NONE 表示取消自動對映。 PARTIAL 表示只會自動對映,沒有定義巢狀結果集和對映結果集。 FULL 會自動對映任意複雜的結果集(無論是否巢狀) NONE、PARTIAL、FULL PARTIAL
autoMappingUnkno wnColumnBehavior 指定自動對映當中未知列(或未知屬性型別)時的行為。 預設是不處理,只有當日志級別達到 WARN 級別或者以下,才會顯示相關日誌,如果處理失敗會丟擲 SqlSessionException 異常 NONE、WARNING、FAILING NONE
defaultExecutorType 配置預設的執行器。SIMPLE 是普通的執行器;REUSE 會重用預處理語句(prepared statements);BATCH 執行器將重用語句並執行批量更新 SIMPLE、REUSE、BATCH SIMPLE
defaultStatementTimeout 設定超時時間,它決定驅動等待資料庫響應的秒數 任何正整數 Not Set (null)
defaultFetchSize 設定資料庫驅動程式預設返回的條數限制,此引數可以重新設定 任何正整數 Not Set (null)
safeRowBoundsEnabled 允許在巢狀語句中使用分頁(RowBounds)。如果允許,設定 false true|false false
safeResultHandlerEnabled 允許在巢狀語句中使用分頁(ResultHandler)。如果允許,設定false true|false true
mapUnderscoreToCamelCase 是否開啟自動駝峰命名規則對映,即從經典資料庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的類似對映 true|false false
localCacheScope MyBatis 利用本地快取機制(Local Cache)防止迴圈引用(circular references)和加速聯復巢狀査詢。 預設值為 SESSION,這種情況下會快取一個會話中執行的所有查詢。若設定值為 STATEMENT,本地會話僅用在語句執行上,對相同 SqlScssion 的不同調用將不會共享資料 SESSION|STATEMENT SESSION
jdbcTypeForNull 當沒有為引數提供特定的 JDBC 型別時,為空值指定 JDBC 型別。某些驅動需要指定列的 JDBC 型別,多數情況直接用一般型別即可,比如 NULL、VARCHAR 或 OTHER NULL、VARCHAR、OTHER OTHER
lazyLoadTriggerMethods 指定哪個物件的方法觸發一次延遲載入 equals、clone、hashCode、toString
defaultScriptingLanguage 指定動態 SQL 生成的預設語言 org.apache.ibatis .script.ing.xmltags .XMLDynamicLanguageDriver
callSettersOnNulls 指定當結果集中值為 null 時,是否呼叫對映物件的 setter(map 物件時為 put)方法,這對於 Map.kcySet() 依賴或 null 值初始化時是有用的。注意,基本型別(int、boolean 等)不能設定成 null true|false false
logPrefix 指定 MyBatis 增加到日誌名稱的字首 任何字串 Not set
loglmpl 指定 MyBatis 所用日誌的具體實現,未指定時將自動査找 SLF4J|LOG4J|LOG4J2|JDK_LOGGING |COMMONS_LOGGING |ST DOUT_LOGGING|NO_LOGGING Not set
proxyFactory 指定 MyBatis 建立具有延遲加栽能力的物件所用到的代理工具 CGLIB|JAVASSIST JAVASSIST (MyBatis 版本為 3.3 及以上的)
vfsImpl 指定 VFS 的實現類 提供 VFS 類的全限定名,如果存在多個,可以使用逗號分隔 Not set
useActualParamName 允許用方法引數中宣告的實際名稱引用引數。要使用此功能,專案必須被編譯為 Java 8 引數的選擇。(從版本 3.4.1 開始可以使用) true|false true

下面給出一個全量的配置樣例,如下所示。

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="multipleResultSetsEnabled" value="true"/>
    <setting name="useColumnLabel" value="true"/>
    <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"/>
    <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>

typeAliases標籤

為了不在任何地方都指定類的全限定名,我們可以使用 typeAliases 標籤定義一個別名。

例如,在 net.bianchengbang.po 包中有一個 Student 類,則該類的全限定名稱為 net.bianchengbang.po.Student。使用 typeAliases標籤定義別名,這樣就不用每次都書寫類的全限定名稱了,程式碼如下。

<typeAliases>
    <typeAlias alias = "Student" type = "net.bianchengbang.po.Student"/>
</typeAliases>

如果需要對同一個包下的多個類定義別名,則可以定義為:

<typeAliases>
    <package name="net.biancheng.po"/>
</typeAliases>

這樣 MyBatis 將掃描 net.biancheng.po 包裡面的類,將其第一個字母變為小寫作為其別名,例如 Student 別名為 studentUser 別名為 user

typeHandlers標籤

typeHandlers 主要將獲取的值合理地轉化為Java型別。在 typeHandler 中,分為 jdbcTypejavaType,其中 jdbcType 用於定義資料庫型別,而javaType用於定義 Java 型別,typeHandler 的作用就是承擔 jdbcType javaType 之間的相互轉換。

MyBatis 支援自定義處理型別,在自定義處理型別時,需要實現 org.apache.ibatis.type.TypeHandler 介面或繼承 org.apache.ibatis.type.BaseTypeHandle 類。詳細可參考官網:http://www.mybatis.org/mybatis-3/zh/configuration.html#typeHandlers

environments標籤

environments 標籤中,可以配置 MyBatis 的多套執行環境,將 SQL 對映到多個不同的資料庫上。

environmentenvironments 的子標籤,用來配置 MyBatis 的一套執行環境,需指定執行環境 ID、事務管理、資料來源配置等相關資訊。

我們可以通過配置多個environment標籤來連線多個數據庫,需要注意的是必須指定其中一個為預設執行環境(通過default指定)。

environment 標籤提供了兩個子標籤,即transactionManager dataSource

transactionManager標籤

MyBatis 支援兩個事務管理器,即 JDBC 和 MANAGED。

如果使用 JDBC 型別的事務管理器,則應用程式伺服器負責事務管理操作,例如提交、回滾等。如果使用 MANAGED 型別的事務管理器,則應用程式伺服器負責管理連線生命週期。

dataSource標籤

用於配置資料庫的連線屬性,例如要連線的資料庫的驅動程式名稱、URL、使用者名稱和密碼等。

dataSource 中的 type 屬性用於指定資料來源型別,有以下 3 種類型。

1)UNPOOLED

UNPOOLED 沒有資料庫連線池,效率低下。MyBatis 需要開啟和關閉每個資料庫操作的連線,它有點慢,通常應用於簡單的應用程式。

2)POOLED

對於 POOLED 資料來源型別,MyBatis 將維護一個數據庫連線池。並且對於每個資料庫的操作,MyBatis 都會使用連線池中的連線,並在操作完成後將它們返回到池中。減少了建立新連線所需的初始連線和身份驗證時間。

3)JNDI

對於 JNDI 的資料來源型別,MyBatis 將從 JNDI 資料來源中獲取連線。

dataSource 標籤示例程式碼如下:

<dataSource type="POOLED">
    <!-- MySQL資料庫驅動 -->
    <property name="driver" value="com.mysql.jdbc.Driver" />
    <!-- 連線資料庫的URL -->
    <property name="url"
        value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8" />
    <property name="username" value="root" />
    <property name="password" value="root" />
</dataSource>

mappers標籤

mappers 標籤用於指定 MyBatis SQL 對映檔案的路徑。

mappermappers 的子標籤,mapper 中的 resource 屬性用於指定 SQL 對映檔案的路徑(類資源路徑)

例如,SQL 對映檔案的名稱是 BlogMapper.xml,它位於名為 mapper 的包中,那麼您可以這樣配置:

<mappers>
    <mapper resource="mapper/BlogMapper.xml"/>
</mappers>

MyBatis Mapper(對映器)

​ 對映器是 MyBatis 中最重要的檔案,檔案中包含一組 SQL 語句(例如查詢、新增、刪除、修改),這些語句稱為對映語句或對映 SQL 語句。

對映器由 Java 介面和 XML 檔案(或註解)共同組成,它的作用如下。

  • 定義引數型別
  • 配置快取
  • 提供 SQL 語句和動態 SQL
  • 定義查詢結果和 POJO 的對映關係

對映器有以下兩種實現方式。

  • 通過 XML 檔案方式實現,比如我們在 mybatis-config.xml 檔案中描述的 XML 檔案,用來生成 mapper。
  • 通過註解的方式實現,使用 Configuration 物件註冊 Mapper 介面。

​ 如果 SQL 語句存在動態 SQL 或者比較複雜,使用註解寫在 Java 檔案裡可讀性差,且增加了維護的成本。所以一般建議使用 XML 檔案配置的方式,避免重複編寫 SQL 語句。

XML實現對映器

XML 定義對映器分為兩個部分:介面和XML。

定義xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
    <resultMap id="blogMap" type="org.mybatis.example.Blog">
        <collection property="id" column="id"></collection>
        <collection property="blogTitle" column="blog_title"></collection>
        <collection property="desc" column="desc"></collection>
    </resultMap>
    <select id="selectBlog" resultType="org.mybatis.example.Blog">
        select * from Blog where id = #{id}
    </select>
</mapper>

下面對上述 XML 檔案進行講解。

  • namespace 用來定義名稱空間,該名稱空間和定義介面的全限定名一致。
  • <select> 元素表明這是一條查詢語句,屬性 id 用來標識這條 SQL。resultType 表示返回的是一個 Website 型別的值。

定義介面

package org.mybatis.example;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BlogMapper {
    Blog selectBlog(int id);
}

新增配置

在 MyBatis 配置檔案中新增以下程式碼。

<mapper resource="mapper/BlogMapper.xml" />

該語句用來引入 XML 檔案,MyBatis 會讀取 BlogMapper.xml 檔案,生成對映器。

註解實現對映器

使用註解的方式實現對映器,只需要在介面中使用 Java 註解,注入 SQL 即可。

package org.mybatis.example;

public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

如果實體和資料庫欄位不一樣需要進行對映

package org.mybatis.example;

import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

public interface BlogMapper {
    @Select(value = "select * from blog where id=#{id}")
    @Results(value = {
            @Result(property = "blogTitle",column = "blog_title")
    })
    public Blog selectBlog(int id);
}

這裡我們使用了 @Select 註解,並且注入了和 XML 中相同的 select 語句。

如果使用註解和 XML 檔案兩種方式同時定義,那麼 XML 方式將覆蓋掉註解方式。

雖然這裡註解的方式看起來比 XML 簡單,但是現實中我們遇到的 SQL 會比該例子複雜得多。如果 SQL 語句中有多個表的關聯、多個查詢條件、級聯、條件分支等,顯然這條 SQL 就會複雜的多,所以並不建議讀者使用這種方式。比如下面這條 SQL。

select * from t_user u
left join t_user_role ur on u.id = ur.user_id
left join t_role r on ur.role_id = r.id
left join t_user_info ui on u.id = ui.user_id
left join t_female_health fh on u.id = fh.user_id
left join t_male_health mh on u.id = mh.user_id
where u.user_name like concat('%', ${userName},'%')
and r.role_name like concat('%', ${roleName},'%')
and u.sex = 1
and ui.head_image is not null;

​ 如果把以上 SQL 放到 @Select註解中,無疑會大大降低程式碼的可讀性。如果同時還要考慮使用動態 SQL 或需要加入其他的邏輯,這樣就使得這個註解更加複雜了,不利於日後的維護和修改。

此外,XML 可以相互引入,而註解是不可以的,所以在一些比較複雜的場景下,使用 XML 方式會更加靈活和方便。因此大部分的企業都以 XML 為主,本教程也會保持一致,以 XML 方式來建立對映器。當然在一些簡單的表和應用中使用註解方式也會比較簡單。

這個介面可以在 XML 中定義,將在 mybatis-config.xml 中配置 XML 的語句修改為以下語句即可。

<mapper resource="com/mybatis/mapper/BlogMapper" />

也可以使用 configuration 物件註冊這個介面,比如:

configuration.addMapper(BlogMapper.class);

示例

Blog

package org.mybatis.example;

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Blog {
    private int id;
    private String blogTitle;
    private String desc;
}

BlogMapper

package org.mybatis.example;

import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

public interface BlogMapper {
    @Select(value = "select * from blog where id=#{id}")
    @Results(value = {
            @Result(property = "blogTitle",column = "blog_title")
    })
    public Blog selectBlog(int id);
}

MainApplication

package org.mybatis.example;

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 java.io.IOException;
import java.io.InputStream;

public class MainApplication {
    public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            try (SqlSession session = sqlSessionFactory.openSession()) {
                session.getConfiguration().addMapper(BlogMapper.class);
                BlogMapper mapper = session.getMapper(BlogMapper.class);
                // 你的應用邏輯程式碼
                Blog blog = mapper.selectBlog(1);
                System.out.println(blog.toString());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

mybatis-config.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">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

MyBatis 對映器的主要元素

下面介紹在對映器中可以定義哪些元素,以及它們的作用。

元素名稱 描述 備註
mapper 對映檔案的根節點,只有 namescape 一個屬性 namescape 作用如下:用於區分不同的 mapper,全域性唯一繫結DAO介面,即面向介面程式設計。當 namescape 繫結某一介面後,可以不用寫該介面的實現類,MyBatis 會通過介面的完整限定名查詢到對應的 mapper 配置來執行 SQL 語句。因此 namescape 的命名必須要跟介面同名。
select 查詢語句,最常用、最複雜的元素之一 可以自定義引數,返回結果集等
insert 插入語句 執行後返回一個整數,代表插入的條數
update 更新語句 執行後返回一個整數,代表更新的條數
delete 刪除語句 執行後返回一個整數,代表刪除的條數
parameterMap 定義引數對映關係 即將被刪除的元素,不建議使用
sql 允許定義一部分的 SQL,然後在各個地方引用它 例如,一張表列名,我們可以一次定義,在多個 SQL 語句中使用
resultMap 用來描述資料庫結果集與物件的對應關係,它是最複雜、最強大的元素 提供對映規則
cache 配置給定名稱空間的快取 -
cache-ref 其它名稱空間快取配置的引用 -

後面文章中會詳細介紹以上元素。

拓展

關於 MyBatis 的 SQL 對映檔案中的 mapper 元素的 namescape 屬性有如下要求。

  • namescape 的命名必須跟某個 DAO 介面同名,同屬於 DAO 層,因此程式碼結構上,對映檔案與該介面應放置在同一 package 下(如 org.mybatis.example.blog),並且習慣上是以 Mapper 結尾(如 BlogMapper.javaBlogMapper.xml)。
  • 不同的 mapper 檔案中子元素的id可以相同,MyBatis 通過 namescape 和子元素的 id 聯合區分。介面中的方法與對映檔案中的 SQL 語句 id 應一 一對應。

構建SqlSessionFactory

從 XML 中構建 SqlSessionFactory

​ 每個基於 MyBatis 的應用都是以一個 SqlSessionFactory 的例項為核心的。SqlSessionFactory 的例項可以通過 SqlSessionFactoryBuilder 獲得。而 SqlSessionFactoryBuilder 則可以從 XML 配置檔案或一個預先配置的 Configuration 例項來構建出 SqlSessionFactory 例項。

​ 從 XML 檔案中構建 SqlSessionFactory 的例項非常簡單,建議使用類路徑下的資原始檔進行配置。 但也可以使用任意的輸入流InputStream例項,比如用檔案路徑字串或 file://URL 構造的輸入流。MyBatis 包含一個名叫 Resources 的工具類,它包含一些實用方法,使得從類路徑或其它位置載入資原始檔更加容易。

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

XML 配置檔案中包含了對 MyBatis 系統的核心設定,包括獲取資料庫連線例項的資料來源DataSource以及決定事務作用域和控制方式的事務管理器TransactionManager。先給出一個簡單的示例:

<?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">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

​ 當然,還有很多可以在 XML 檔案中配置的選項,上面的示例僅羅列了最關鍵的部分。 注意 XML 頭部的宣告,它用來驗證 XML 文件的正確性。environment 元素體中包含了事務管理和連線池的配置。mappers 元素則包含了一組對映器(mapper),這些對映器的 XML 對映檔案包含了 SQL 程式碼和對映定義資訊。

示例

使用IDEA建立Maven專案

引入依賴

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.8</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

resources資料夾下建立mybatis-config.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">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/BlogMapper.xml"/>
    </mappers>
</configuration>

BlogMapper.xml

resources/mapper資料夾下建立BlogMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
    <resultMap id="blogMap" type="org.mybatis.example.Blog">
        <collection property="id" column="id"></collection>
        <collection property="blogTitle" column="blog_title"></collection>
        <collection property="desc" column="desc"></collection>
    </resultMap>
    <select id="selectBlog" resultType="org.mybatis.example.Blog">
        select * from Blog where id = #{id}
    </select>
</mapper>

以下所有檔案在org.mybatis.example包下

MainApplication.java

package org.mybatis.example;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MainApplication {
    public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Blog.java

package org.mybatis.example;

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Blog {
    private int id;
    private String blogTitle;
    private String desc;
}

BlogMapper.java

package org.mybatis.example;

import org.apache.ibatis.annotations.Mapper;

public interface BlogMapper {
    Blog selectBlog(int id);
}
	

如果一直Could not find resource mapper/BlogMapper.xml請檢查BlogMapper.xml是否在resources/mapper目錄下

檢查BlogMapper.xml名稱是否正確。如果你安裝了MyBatisX檔名稱不對也會有小鳥的標準。

包括但不限於這種沒有後綴的名稱BlogMapper

建議XML檔案不要寫在java目錄中

不使用 XML 構建 SqlSessionFactory

​ 如果你更願意直接從 Java 程式碼而不是 XML 檔案中建立配置,或者想要建立你自己的配置建造器,MyBatis 也提供了完整的配置類,提供了所有與 XML 檔案等價的配置項。

DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

​ 注意該例中,configuration 添加了一個對映器類(mapper class)。對映器類是 Java 類,它們包含 SQL 對映註解從而避免依賴 XML 檔案。不過,由於 Java 註解的一些限制以及某些 MyBatis 對映的複雜性,要使用大多數高階對映(比如:巢狀聯合對映),仍然需要使用 XML 配置。有鑑於此,如果存在一個同名 XML 配置檔案,MyBatis 會自動查詢並載入它(在這個例子中,基於類路徑和 BlogMapper.class 的類名,會載入 BlogMapper.xml)。

從 SqlSessionFactory 中獲取 SqlSession

既然有了 SqlSessionFactory,顧名思義,我們可以從中獲得 SqlSession 的例項。SqlSession 提供了在資料庫執行 SQL 命令所需的所有方法。你可以通過 SqlSession 例項來直接執行已對映的 SQL 語句。例如:

try (SqlSession session = sqlSessionFactory.openSession()) {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}

對於像 BlogMapper 這樣的對映器類來說,還有另一種方法來完成語句對映。 它們對映的語句可以不用 XML 來配置,而可以使用 Java 註解來配置。比如,上面的 XML 示例可以被替換成如下的配置:

package org.mybatis.example;

public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

示例

package org.mybatis.example;

import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;

public class MainApplication {
    public static void main(String[] args) {
            //建立連線池
            DataSource dataSource = new PooledDataSource("com.mysql.cj.jdbc.Driver", "jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=utf8", "root", "123456");
            //事務
            TransactionFactory transactionFactory = new JdbcTransactionFactory();
            //建立環境
            Environment environment = new Environment("development", transactionFactory, dataSource);
            // 建立配置
            Configuration configuration = new Configuration(environment);
            // 加入資源(Mapper介面)
            configuration.addMapper(BlogMapper.class);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
            SqlSession session = sqlSessionFactory.openSession();
            try {
                //statement:sql唯一標識(mapper.xml對映檔案中的id標識)
                //parament:引數
                // 你的應用邏輯程式碼
                Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog",1);
                System.out.println(blog.toString());
                //操作資料時,需要有提交操作
                session.commit();
            } finally {
                session.close();
            }
    }
}

​ 該例中,configuration 添加了一個對映器類(mapper class)。對映器類是 Java 類,它們包含 SQL 對映語句的註解從而避免依賴 XML 檔案。不過,由於 Java 註解的一些限制以及某些 MyBatis 對映的複雜性,要使用大多數高階對映(比如:巢狀聯合對映),仍然需要使用 XML 配置。有鑑於此,如果存在一個同名 XML 配置檔案,MyBatis 會自動查詢並載入它(在這個例子中,基於類路徑和 BlogMapper.class 的類名,會載入 BlogMapper.xml)。

此處必須要把BlogMapper.class 和 BlogMapper.xml 放在同一個目錄下,因為在原始碼中寫死了讀同一路徑xml。

org.mybatis.example包下建立BlogMapper.xml檔案

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
    <resultMap id="blogMap" type="org.mybatis.example.Blog">
        <collection property="id" column="id"></collection>
        <collection property="blogTitle" column="blog_title"></collection>
        <collection property="desc" column="desc"></collection>
    </resultMap>
    <select id="selectBlog" resultType="org.mybatis.example.Blog">
        select * from Blog where id = #{id}
    </select>
</mapper>

若出現一下錯誤說明xml沒有編譯

Error querying database.  Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for org.mybatis.example.BlogMapper.selectBlog

在pom.xml檔案中加入

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

重新整理maven