MyBatis 3 Java API-SqlSession

2022-04-11 14:50 更新

SqlSession

正如之前所提到的,?SqlSession ?在 MyBatis 中是非常強(qiáng)大的一個(gè)類。它包含了所有執(zhí)行語句、提交或回滾事務(wù)以及獲取映射器實(shí)例的方法。

?SqlSession ?類的方法超過了 20 個(gè),為了方便理解,我們將它們分成幾種組別。

語句執(zhí)行方法

這些方法被用來執(zhí)行定義在 SQL 映射 XML 文件中的 SELECT、INSERT、UPDATE 和 DELETE 語句。你可以通過名字快速了解它們的作用,每一方法都接受語句的 ID 以及參數(shù)對象,參數(shù)可以是原始類型(支持自動(dòng)裝箱或包裝類)、JavaBean、POJO 或 Map。

<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<T> Cursor<T> selectCursor(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)

?selectOne ?和 ?selectList ?的不同僅僅是 ?selectOne ?必須返回一個(gè)對象或 ?null ?值。如果返回值多于一個(gè),就會(huì)拋出異常。如果你不知道返回對象會(huì)有多少,請使用 ?selectList?。如果需要查看某個(gè)對象是否存在,最好的辦法是查詢一個(gè) ?count ?值(0 或 1)。?selectMap ?稍微特殊一點(diǎn),它會(huì)將返回對象的其中一個(gè)屬性作為 ?key ?值,將對象作為 ?value ?值,從而將多個(gè)結(jié)果集轉(zhuǎn)為 ?Map ?類型值。由于并不是所有語句都需要參數(shù),所以這些方法都具有一個(gè)不需要參數(shù)的重載形式。

游標(biāo)(?Cursor?)與列表(?List?)返回的結(jié)果相同,不同的是,游標(biāo)借助迭代器實(shí)現(xiàn)了數(shù)據(jù)的惰性加載。

try (Cursor<MyEntity> entities = session.selectCursor(statement, param)) {
   for (MyEntity entity:entities) {
      // 處理單個(gè)實(shí)體
   }
}

insert、update 以及 delete 方法返回的值表示受該語句影響的行數(shù)。

<T> T selectOne(String statement)
<E> List<E> selectList(String statement)
<T> Cursor<T> selectCursor(String statement)
<K,V> Map<K,V> selectMap(String statement, String mapKey)
int insert(String statement)
int update(String statement)
int delete(String statement)

最后,還有 select 方法的三個(gè)高級版本,它們允許你限制返回行數(shù)的范圍,或是提供自定義結(jié)果處理邏輯,通常在數(shù)據(jù)集非常龐大的情形下使用。

<E> List<E> selectList (String statement, Object parameter, RowBounds rowBounds)
<T> Cursor<T> selectCursor(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)

?RowBounds ?參數(shù)會(huì)告訴 MyBatis 略過指定數(shù)量的記錄,并限制返回結(jié)果的數(shù)量。?RowBounds ?類的 ?offset ?和 ?limit ?值只有在構(gòu)造函數(shù)時(shí)才能傳入,其它時(shí)候是不能修改的。

int offset = 100;
int limit = 25;
RowBounds rowBounds = new RowBounds(offset, limit);

數(shù)據(jù)庫驅(qū)動(dòng)決定了略過記錄時(shí)的查詢效率。為了獲得最佳的性能,建議將 ?ResultSet ?類型設(shè)置為 ?SCROLL_SENSITIVE ?或 ?SCROLL_INSENSITIVE?(換句話說:不要使用 ?FORWARD_ONLY?)。

?ResultHandler ?參數(shù)允許自定義每行結(jié)果的處理過程。你可以將它添加到 List 中、創(chuàng)建 Map 和 Set,甚至丟棄每個(gè)返回值,只保留計(jì)算后的統(tǒng)計(jì)結(jié)果。你可以使用 ?ResultHandler ?做很多事,這其實(shí)就是 MyBatis 構(gòu)建 結(jié)果列表的內(nèi)部實(shí)現(xiàn)辦法。

從版本 3.4.6 開始,?ResultHandler ?會(huì)在存儲(chǔ)過程的 ?REFCURSOR ?輸出參數(shù)中傳遞使用的 ?CALLABLE ?語句。

它的接口很簡單:

package org.apache.ibatis.session;
public interface ResultHandler<T> {
  void handleResult(ResultContext<? extends T> context);
}

?ResultContext ?參數(shù)允許你訪問結(jié)果對象和當(dāng)前已被創(chuàng)建的對象數(shù)目,另外還提供了一個(gè)返回值為 ?Boolean ?的 ?stop ?方法,你可以使用此 ?stop ?方法來停止 MyBatis 加載更多的結(jié)果。

使用 ?ResultHandler ?的時(shí)候需要注意以下兩個(gè)限制:

  • 使用帶 ?ResultHandler ?參數(shù)的方法時(shí),收到的數(shù)據(jù)不會(huì)被緩存。
  • 當(dāng)使用高級的結(jié)果映射集(?resultMap?)時(shí),MyBatis 很可能需要數(shù)行結(jié)果來構(gòu)造一個(gè)對象。如果你使用了 ?ResultHandler?,你可能會(huì)接收到關(guān)聯(lián)(?association?)或者集合(?collection?)中尚未被完整填充的對象。

立即批量更新方法

當(dāng)你將 ?ExecutorType ?設(shè)置為 ?ExecutorType.BATCH? 時(shí),可以使用這個(gè)方法清除(執(zhí)行)緩存在 JDBC 驅(qū)動(dòng)類中的批量更新語句。

List<BatchResult> flushStatements()

事務(wù)控制方法

有四個(gè)方法用來控制事務(wù)作用域。當(dāng)然,如果你已經(jīng)設(shè)置了自動(dòng)提交或你使用了外部事務(wù)管理器,這些方法就沒什么作用了。然而,如果你正在使用由 ?Connection ?實(shí)例控制的 JDBC 事務(wù)管理器,那么這四個(gè)方法就會(huì)派上用場:

void commit()
void commit(boolean force)
void rollback()
void rollback(boolean force)

默認(rèn)情況下 MyBatis 不會(huì)自動(dòng)提交事務(wù),除非它偵測到調(diào)用了插入、更新或刪除方法改變了數(shù)據(jù)庫。如果你沒有使用這些方法提交修改,那么你可以在 ?commit ?和 ?rollback ?方法參數(shù)中傳入 ?true ?值,來保證事務(wù)被正常提交(注意,在自動(dòng)提交模式或者使用了外部事務(wù)管理器的情況下,設(shè)置 ?force ?值對 ?session ?無效)。大部分情況下你無需調(diào)用 ?rollback()?,因?yàn)?nbsp;MyBatis 會(huì)在你沒有調(diào)用 ?commit ?時(shí)替你完成回滾操作。不過,當(dāng)你要在一個(gè)可能多次提交或回滾的 ?session ?中詳細(xì)控制事務(wù),回滾操作就派上用場了。

本地緩存

Mybatis 使用到了兩種緩存:本地緩存(?local cache?)和二級緩存(?second level cache?)。

每當(dāng)一個(gè)新 ?session ?被創(chuàng)建,MyBatis 就會(huì)創(chuàng)建一個(gè)與之相關(guān)聯(lián)的本地緩存。任何在 ?session ?執(zhí)行過的查詢結(jié)果都會(huì)被保存在本地緩存中,所以,當(dāng)再次執(zhí)行參數(shù)相同的相同查詢時(shí),就不需要實(shí)際查詢數(shù)據(jù)庫了。本地緩存將會(huì)在做出修改、事務(wù)提交或回滾,以及關(guān)閉 ?session ?時(shí)清空。

默認(rèn)情況下,本地緩存數(shù)據(jù)的生命周期等同于整個(gè) session 的周期。由于緩存會(huì)被用來解決循環(huán)引用問題和加快重復(fù)嵌套查詢的速度,所以無法將其完全禁用。但是你可以通過設(shè)置 ?localCacheScope=STATEMENT? 來只在語句執(zhí)行時(shí)使用緩存。

注意,如果 ?localCacheScope ?被設(shè)置為 ?SESSION?,對于某個(gè)對象,MyBatis 將返回在本地緩存中唯一對象的引用。對返回的對象(例如 ?list?)做出的任何修改將會(huì)影響本地緩存的內(nèi)容,進(jìn)而將會(huì)影響到在本次 ?session ?中從緩存返回的值。因此,不要對 MyBatis 所返回的對象作出更改,以防后患。

你可以隨時(shí)調(diào)用以下方法來清空本地緩存:

void clearCache()

確保 SqlSession 被關(guān)閉

void close()

對于你打開的任何 ?session?,你都要保證它們被妥善關(guān)閉,這很重要。保證妥善關(guān)閉的最佳代碼模式是這樣的:

SqlSession session = sqlSessionFactory.openSession();
try (SqlSession session = sqlSessionFactory.openSession()) {
    // 假設(shè)下面三行代碼是你的業(yè)務(wù)邏輯
    session.insert(...);
    session.update(...);
    session.delete(...);
    session.commit();
}

和 ?SqlSessionFactory ?一樣,你可以調(diào)用當(dāng)前使用的 ?SqlSession ?的 ?getConfiguration ?方法來獲得 ?Configuration ?實(shí)例。

Configuration getConfiguration()

使用映射器

<T> T getMapper(Class<T> type)

上述的各個(gè) insert、update、delete 和 select 方法都很強(qiáng)大,但也有些繁瑣,它們并不符合類型安全,對你的 IDE 和單元測試也不是那么友好。因此,使用映射器類來執(zhí)行映射語句是更常見的做法。

我們已經(jīng)在之前的入門章節(jié)中見到過一個(gè)使用映射器的示例。一個(gè)映射器類就是一個(gè)僅需聲明與 ?SqlSession ?方法相匹配方法的接口。下面的示例展示了一些方法簽名以及它們是如何映射到 ?SqlSession ?上的。

public interface AuthorMapper {
  // (Author) selectOne("selectAuthor",5);
  Author selectAuthor(int id);
  // (List<Author>) selectList(“selectAuthors”)
  List<Author> selectAuthors();
  // (Map<Integer,Author>) selectMap("selectAuthors", "id")
  @MapKey("id")
  Map<Integer, Author> selectAuthors();
  // insert("insertAuthor", author)
  int insertAuthor(Author author);
  // updateAuthor("updateAuthor", author)
  int updateAuthor(Author author);
  // delete("deleteAuthor",5)
  int deleteAuthor(int id);
}

總之,每個(gè)映射器方法簽名應(yīng)該匹配相關(guān)聯(lián)的 ?SqlSession ?方法,字符串參數(shù) ID 無需匹配。而是由方法名匹配映射語句的 ID。

此外,返回類型必須匹配期望的結(jié)果類型,返回單個(gè)值時(shí),返回類型應(yīng)該是返回值的類,返回多個(gè)值時(shí),則為數(shù)組或集合類,另外也可以是游標(biāo)(?Cursor?)。所有常用的類型都是支持的,包括:原始類型、?Map?、?POJO ?和 ?JavaBean?。

映射器接口不需要去實(shí)現(xiàn)任何接口或繼承自任何類。只要方法簽名可以被用來唯一識(shí)別對應(yīng)的映射語句就可以了。

映射器接口可以繼承自其他接口。在使用 XML 來綁定映射器接口時(shí),保證語句處于合適的命名空間中即可。唯一的限制是,不能在兩個(gè)具有繼承關(guān)系的接口中擁有相同的方法簽名(這是潛在的危險(xiǎn)做法,不可?。?。

你可以傳遞多個(gè)參數(shù)給一個(gè)映射器方法。在多個(gè)參數(shù)的情況下,默認(rèn)它們將會(huì)以 ?param ?加上它們在參數(shù)列表中的位置來命名,比如:?#{param1}?、?#{param2}?等。如果你想(在有多個(gè)參數(shù)時(shí))自定義參數(shù)的名稱,那么你可以在參數(shù)上使用 ?@Param("paramName")? 注解。

你也可以給方法傳遞一個(gè) ?RowBounds ?實(shí)例來限制查詢結(jié)果。

映射器注解

設(shè)計(jì)初期的 MyBatis 是一個(gè) XML 驅(qū)動(dòng)的框架。配置信息是基于 XML 的,映射語句也是定義在 XML 中的。而在 MyBatis 3 中,我們提供了其它的配置方式。MyBatis 3 構(gòu)建在全面且強(qiáng)大的基于 Java 語言的配置 API 之上。它是 XML 和注解配置的基礎(chǔ)。注解提供了一種簡單且低成本的方式來實(shí)現(xiàn)簡單的映射語句。

不幸的是,Java 注解的表達(dá)能力和靈活性十分有限。盡管我們花了很多時(shí)間在調(diào)查、設(shè)計(jì)和試驗(yàn)上,但最強(qiáng)大的 MyBatis 映射并不能用注解來構(gòu)建——我們真沒開玩笑。而 C# 屬性就沒有這些限制,因此 MyBatis.NET 的配置會(huì)比 XML 有更大的選擇余地。雖說如此,基于 Java 注解的配置還是有它的好處的。

注解如下表所示:

注解 使用對象 XML 等價(jià)形式 描述
@CacheNamespace <cache> 為給定的命名空間(比如類)配置緩存。屬性:implemetation、evictionflushInterval、size、readWriteblocking、properties。
@Property N/A <property> 指定參數(shù)值或占位符(placeholder)(該占位符能被 mybatis-config.xml 內(nèi)的配置屬性替換)。屬性:namevalue。(僅在 MyBatis 3.4.2 以上可用)
@CacheNamespaceRef <cacheRef> 引用另外一個(gè)命名空間的緩存以供使用。注意,即使共享相同的全限定類名,在 XML 映射文件中聲明的緩存仍被識(shí)別為一個(gè)獨(dú)立的命名空間。屬性:value、name。如果你使用了這個(gè)注解,你應(yīng)設(shè)置 value 或者 name 屬性的其中一個(gè)。value 屬性用于指定能夠表示該命名空間的 Java 類型(命名空間名就是該 Java 類型的全限定類名),name 屬性(這個(gè)屬性僅在 MyBatis 3.4.2 以上可用)則直接指定了命名空間的名字。
@ConstructorArgs 方法 <constructor> 收集一組結(jié)果以傳遞給一個(gè)結(jié)果對象的構(gòu)造方法。屬性:value,它是一個(gè) Arg 數(shù)組。
@Arg N/A
  • <arg>
  • <idArg>
ConstructorArgs 集合的一部分,代表一個(gè)構(gòu)造方法參數(shù)。屬性:id、columnjavaType、jdbcType、typeHandler、select、resultMap。id 屬性和 XML 元素 <idArg> 相似,它是一個(gè)布爾值,表示該屬性是否用于唯一標(biāo)識(shí)和比較對象。從版本 3.5.4 開始,該注解變?yōu)榭芍貜?fù)注解。
@TypeDiscriminator 方法 <discriminator> 決定使用何種結(jié)果映射的一組取值(case)。屬性:columnjavaType、jdbcTypetypeHandler、cases。cases 屬性是一個(gè) Case 的數(shù)組。
@Case N/A <case> 表示某個(gè)值的一個(gè)取值以及該取值對應(yīng)的映射。屬性:value、type、results。results 屬性是一個(gè) Results 的數(shù)組,因此這個(gè)注解實(shí)際上和 ResultMap 很相似,由下面的 Results 注解指定。
@Results 方法 <resultMap> 一組結(jié)果映射,指定了對某個(gè)特定結(jié)果列,映射到某個(gè)屬性或字段的方式。屬性:value、id。value 屬性是一個(gè) Result 注解的數(shù)組。而 id 屬性則是結(jié)果映射的名稱。從版本 3.5.4 開始,該注解變?yōu)榭芍貜?fù)注解。
@Result N/A
  • <result>
  • <id>
在列和屬性或字段之間的單個(gè)結(jié)果映射。屬性:id、column、javaTypejdbcType、typeHandler、onemany。id 屬性和 XML 元素 <id> 相似,它是一個(gè)布爾值,表示該屬性是否用于唯一標(biāo)識(shí)和比較對象。one 屬性是一個(gè)關(guān)聯(lián),和 <association> 類似,而 many 屬性則是集合關(guān)聯(lián),和 <collection> 類似。這樣命名是為了避免產(chǎn)生名稱沖突。
@One N/A <association> 復(fù)雜類型的單個(gè)屬性映射。屬性: select,指定可加載合適類型實(shí)例的映射語句(也就是映射器方法)全限定名; fetchType,指定在該映射中覆蓋全局配置參數(shù) ?lazyLoadingEnabled?; ?resultMap?(從 3.5.5 開始可用),它是從選擇結(jié)果映射到單個(gè)容器對象的結(jié)果映射的完全限定名稱; ?columnPrefix?(從 3.5.5 開始可用),它是用于分組選擇列的列前綴 嵌套結(jié)果圖。提示 注解 API 不支持聯(lián)合映射。這是由于 Java 注解不允許產(chǎn)生循環(huán)引用。
@Many N/A <collection> 復(fù)雜類型的集合屬性映射。屬性: select,指定可加載合適類型實(shí)例集合的映射語句(也就是映射器方法)全限定名; fetchType,指定在該映射中覆蓋全局配置參數(shù) lazyLoadingEnabled resultMap (從 3.5.5 開始可用),它是從選擇結(jié)果映射到集合對象的結(jié)果映射的完全限定名稱; ?columnPrefix?(從 3.5.5 開始可用),它是用于在嵌套結(jié)果映射中對選擇列進(jìn)行分組的列前綴。提示 注解 API 不支持聯(lián)合映射。這是由于 Java 注解不允許產(chǎn)生循環(huán)引用。
@MapKey 方法 供返回值為 Map 的方法使用的注解。它使用對象的某個(gè)屬性作為 key,將對象 List 轉(zhuǎn)化為 Map。屬性:value,指定作為 Map 的 key 值的對象屬性名。
@Options 方法 映射語句的屬性 該注解允許你指定大部分開關(guān)和配置選項(xiàng),它們通常在映射語句上作為屬性出現(xiàn)。與在注解上提供大量的屬性相比,Options 注解提供了一致、清晰的方式來指定選項(xiàng)。屬性:useCache=true、flushCache=FlushCachePolicy.DEFAULTresultSetType=DEFAULT、statementType=PREPARED、fetchSize=-1、timeout=-1useGeneratedKeys=false、keyProperty=""、keyColumn=""、resultSets=""databaseId=""。注意,Java 注解無法指定 null 值。因此,一旦你使用了 Options 注解,你的語句就會(huì)被上述屬性的默認(rèn)值所影響。要注意避免默認(rèn)值帶來的非預(yù)期行為。 ?databaseId?(自 3.5.5 起可用),如果配置了 ?DatabaseIdProvider?,MyBatis 使用沒有 ?databaseId ?屬性或與當(dāng)前匹配的 ?databaseId ?的選項(xiàng)。 如果發(fā)現(xiàn)有或沒有 ?databaseId?,后者將被丟棄。
       注意:keyColumn 屬性只在某些數(shù)據(jù)庫中有效(如 Oracle、PostgreSQL 等)。要了解更多關(guān)于 keyColumn 和 keyProperty 可選值信息,請查看“insert, update 和 delete”一節(jié)。
  • @Insert
  • @Update
  • @Delete
  • @Select
方法
  • <insert>
  • <update>
  • <delete>
  • <select>
每個(gè)注解分別代表將會(huì)被執(zhí)行的 SQL 語句。它們用字符串?dāng)?shù)組(或單個(gè)字符串)作為參數(shù)。如果傳遞的是字符串?dāng)?shù)組,字符串?dāng)?shù)組會(huì)被連接成單個(gè)完整的字符串,每個(gè)字符串之間加入一個(gè)空格。這有效地避免了用 Java 代碼構(gòu)建 SQL 語句時(shí)產(chǎn)生的“丟失空格”問題。當(dāng)然,你也可以提前手動(dòng)連接好字符串。屬性:value,指定用來組成單個(gè) SQL 語句的字符串?dāng)?shù)組。 ?databaseId?(從 3.5.5 開始可用),如果配置了 ?DatabaseIdProvider?,MyBatis 使用沒有 ?databaseId ?屬性或 ?databaseId ?與當(dāng)前匹配的語句。 如果發(fā)現(xiàn)有或沒有 ?databaseId?,后者將被丟棄。
  • @InsertProvider
  • @UpdateProvider
  • @DeleteProvider
  • @SelectProvider
方法
  • <insert>
  • <update>
  • <delete>
  • <select>
允許構(gòu)建動(dòng)態(tài) SQL。這些備選的 SQL 注解允許你指定返回 SQL 語句的類和方法,以供運(yùn)行時(shí)執(zhí)行。(從 MyBatis 3.4.6 開始,可以使用 CharSequence 代替 String 來作為返回類型)。當(dāng)執(zhí)行映射語句時(shí),MyBatis 會(huì)實(shí)例化注解指定的類,并調(diào)用注解指定的方法。你可以通過 ProviderContext 傳遞映射方法接收到的參數(shù)、"Mapper interface type" 和 "Mapper method"(僅在 MyBatis 3.4.5 以上支持)作為參數(shù)。(MyBatis 3.4 以上支持傳入多個(gè)參數(shù)) 屬性:value、typemethod、databaseId。 value and type 屬性用于指定類名 (?type ?屬性是 ?value ?的別名,您必須指定其中之一。 但是當(dāng)將 ?defaultSqlProviderType ?指定為全局配置時(shí),這兩個(gè)屬性都可以省略)。 method 用于指定該類的方法名(從版本 3.5.1 開始,可以省略 method 屬性,MyBatis 將會(huì)使用 ProviderMethodResolver 接口解析方法的具體實(shí)現(xiàn)。如果解析失敗,MyBatis 將會(huì)使用名為 provideSql 的降級實(shí)現(xiàn))。提示 接下來的“SQL 語句構(gòu)建器”一章將會(huì)討論該話題,以幫助你以更清晰、更便于閱讀的方式構(gòu)建動(dòng)態(tài) SQL。 ?databaseId?(自 3.5.5 起可用),如果配置了 ?DatabaseIdProvider?,MyBatis 將使用沒有 ?databaseId ?屬性或與當(dāng)前匹配的 ?databaseId ?的提供程序方法。 如果發(fā)現(xiàn)有或沒有 ?databaseId?,后者將被丟棄。
@Param 參數(shù) N/A 如果你的映射方法接受多個(gè)參數(shù),就可以使用這個(gè)注解自定義每個(gè)參數(shù)的名字。否則在默認(rèn)情況下,除 RowBounds 以外的參數(shù)會(huì)以 "param" 加參數(shù)位置被命名。例如 #{param1}#{param2}。如果使用了 @Param("person"),參數(shù)就會(huì)被命名為 #{person}。
@SelectKey 方法 <selectKey> 這個(gè)注解的功能與 <selectKey> 標(biāo)簽完全一致。該注解只能在 @Insert 或 @InsertProvider 或 @Update 或 @UpdateProvider 標(biāo)注的方法上使用,否則將會(huì)被忽略。如果標(biāo)注了 @SelectKey 注解,MyBatis 將會(huì)忽略掉由 @Options 注解所設(shè)置的生成主鍵或設(shè)置(configuration)屬性。屬性:statement 以字符串?dāng)?shù)組形式指定將會(huì)被執(zhí)行的 SQL 語句,keyProperty 指定作為參數(shù)傳入的對象對應(yīng)屬性的名稱,該屬性將會(huì)更新成新的值,before 可以指定為 true 或 false 以指明 SQL 語句應(yīng)被在插入語句的之前還是之后執(zhí)行。resultType 則指定 keyProperty 的 Java 類型。statementType 則用于選擇語句類型,可以選擇 STATEMENTPREPARED 或 CALLABLE 之一,它們分別對應(yīng)于 Statement、PreparedStatement 和 CallableStatement。默認(rèn)值是 PREPARED。 ?databaseId?(從 3.5.5 開始可用),如果配置了 ?DatabaseIdProvider?,MyBatis 將使用沒有 ?databaseId ?屬性或 ?databaseId ?與當(dāng)前匹配的語句。 如果發(fā)現(xiàn)有或沒有 ?databaseId?,后者將被丟棄。
@ResultMap 方法 N/A 這個(gè)注解為 @Select 或者 @SelectProvider 注解指定 XML 映射中 <resultMap> 元素的 id。這使得注解的 select 可以復(fù)用已在 XML 中定義的 ResultMap。如果標(biāo)注的 select 注解中存在 @Results 或者 @ConstructorArgs 注解,這兩個(gè)注解將被此注解覆蓋。
@ResultType 方法 N/A 在使用了結(jié)果處理器的情況下,需要使用此注解。由于此時(shí)的返回類型為 void,所以 Mybatis 需要有一種方法來判斷每一行返回的對象類型。如果在 XML 有對應(yīng)的結(jié)果映射,請使用 @ResultMap 注解。如果結(jié)果類型在 XML 的 <select> 元素中指定了,就不需要使用其它注解了。否則就需要使用此注解。比如,如果一個(gè)標(biāo)注了 @Select 的方法想要使用結(jié)果處理器,那么它的返回類型必須是 void,并且必須使用這個(gè)注解(或者 @ResultMap)。這個(gè)注解僅在方法返回類型是 void 的情況下生效。
@Flush 方法 N/A 如果使用了這個(gè)注解,定義在 Mapper 接口中的方法就能夠調(diào)用 SqlSession#flushStatements() 方法。(Mybatis 3.3 以上可用)

映射注解示例

這個(gè)例子展示了如何使用 ?@SelectKey? 注解來在插入前讀取數(shù)據(jù)庫序列的值:

@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
int insertTable3(Name name);

這個(gè)例子展示了如何使用 ?@SelectKey? 注解來在插入后讀取數(shù)據(jù)庫自增列的值:

@Insert("insert into table2 (name) values(#{name})")
@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
int insertTable2(Name name);

這個(gè)例子展示了如何使用 ?@Flush? 注解來調(diào)用 ?SqlSession#flushStatements()?:

@Flush
List<BatchResult> flush();

這些例子展示了如何通過指定 ?@Result? 的 id 屬性來命名結(jié)果集:

@Results(id = "userResult", value = {
  @Result(property = "id", column = "uid", id = true),
  @Result(property = "firstName", column = "first_name"),
  @Result(property = "lastName", column = "last_name")
})
@Select("select * from users where id = #{id}")
User getUserById(Integer id);

@Results(id = "companyResults")
@ConstructorArgs({
  @Arg(column = "cid", javaType = Integer.class, id = true),
  @Arg(column = "name", javaType = String.class)
})
@Select("select * from company where id = #{id}")
Company getCompanyById(Integer id);

這個(gè)例子展示了如何使用單個(gè)參數(shù)的 ?@SqlProvider? 注解:

@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(String name);

class UserSqlBuilder {
  public static String buildGetUsersByName(final String name) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      if (name != null) {
        WHERE("name like #{value} || '%'");
      }
      ORDER_BY("id");
    }}.toString();
  }
}

這個(gè)例子展示了如何使用多個(gè)參數(shù)的 ?@SqlProvider? 注解:

@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(
    @Param("name") String name, @Param("orderByColumn") String orderByColumn);

class UserSqlBuilder {

  // 如果不使用 @Param,就應(yīng)該定義與 mapper 方法相同的參數(shù)
  public static String buildGetUsersByName(
      final String name, final String orderByColumn) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      WHERE("name like #{name} || '%'");
      ORDER_BY(orderByColumn);
    }}.toString();
  }

  // 如果使用 @Param,就可以只定義需要使用的參數(shù)
  public static String buildGetUsersByName(@Param("orderByColumn") final String orderByColumn) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      WHERE("name like #{name} || '%'");
      ORDER_BY(orderByColumn);
    }}.toString();
  }
}

這個(gè)例子顯示使用全局配置(自 3.5.6 起可用)將 sql 提供程序類共享給所有映射器方法的用法:

Configuration configuration = new Configuration();
configuration.setDefaultSqlProviderType(TemplateFilePathProvider.class); // Specify an sql provider class for sharing on all mapper methods
// ...
// Can omit the type/value attribute on sql provider annotation
// If omit it, the MyBatis apply the class that specified on defaultSqlProviderType.
public interface UserMapper {

  @SelectProvider // Same with @SelectProvider(TemplateFilePathProvider.class)
  User findUser(int id);

  @InsertProvider // Same with @InsertProvider(TemplateFilePathProvider.class)
  void createUser(User user);

  @UpdateProvider // Same with @UpdateProvider(TemplateFilePathProvider.class)
  void updateUser(User user);

  @DeleteProvider // Same with @DeleteProvider(TemplateFilePathProvider.class)
  void deleteUser(int id);
}

以下例子展示了 ?ProviderMethodResolver?(3.5.1 后可用)的默認(rèn)實(shí)現(xiàn)使用方法:

@SelectProvider(UserSqlProvider.class)
List<User> getUsersByName(String name);

// 在你的 provider 類中實(shí)現(xiàn) ProviderMethodResolver 接口
class UserSqlProvider implements ProviderMethodResolver {
  // 默認(rèn)實(shí)現(xiàn)中,會(huì)將映射器方法的調(diào)用解析到實(shí)現(xiàn)的同名方法上
  public static String getUsersByName(final String name) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      if (name != null) {
        WHERE("name like #{value} || '%'");
      }
      ORDER_BY("id");
    }}.toString();
  }
}

這個(gè)例子顯示語句注釋上的 ?databaseId ?屬性的用法(自 3.5.5 起可用):

@Select(value = "SELECT SYS_GUID() FROM dual", databaseId = "oracle") // Use this statement if DatabaseIdProvider provide "oracle"
@Select(value = "SELECT uuid_generate_v4()", databaseId = "postgres") // Use this statement if DatabaseIdProvider provide "postgres"
@Select("SELECT RANDOM_UUID()") // Use this statement if the DatabaseIdProvider not configured or not matches databaseId
String generateId();


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)