MyBatis 3 Java API-SqlSession

2022-04-11 14:50 更新

SqlSession

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

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

語句執(zhí)行方法

這些方法被用來執(zhí)行定義在 SQL 映射 XML 文件中的 SELECT、INSERT、UPDATE 和 DELETE 語句。你可以通過名字快速了解它們的作用,每一方法都接受語句的 ID 以及參數(shù)對象,參數(shù)可以是原始類型(支持自動裝箱或包裝類)、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 ?必須返回一個對象或 ?null ?值。如果返回值多于一個,就會拋出異常。如果你不知道返回對象會有多少,請使用 ?selectList?。如果需要查看某個對象是否存在,最好的辦法是查詢一個 ?count ?值(0 或 1)。?selectMap ?稍微特殊一點(diǎn),它會將返回對象的其中一個屬性作為 ?key ?值,將對象作為 ?value ?值,從而將多個結(jié)果集轉(zhuǎn)為 ?Map ?類型值。由于并不是所有語句都需要參數(shù),所以這些方法都具有一個不需要參數(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) {
      // 處理單個實(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 方法的三個高級版本,它們允許你限制返回行數(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ù)會告訴 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ū)動決定了略過記錄時(shí)的查詢效率。為了獲得最佳的性能,建議將 ?ResultSet ?類型設(shè)置為 ?SCROLL_SENSITIVE ?或 ?SCROLL_INSENSITIVE?(換句話說:不要使用 ?FORWARD_ONLY?)。

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

從版本 3.4.6 開始,?ResultHandler ?會在存儲過程的 ?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ù)目,另外還提供了一個返回值為 ?Boolean ?的 ?stop ?方法,你可以使用此 ?stop ?方法來停止 MyBatis 加載更多的結(jié)果。

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

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

立即批量更新方法

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

List<BatchResult> flushStatements()

事務(wù)控制方法

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

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

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

本地緩存

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

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

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

注意,如果 ?localCacheScope ?被設(shè)置為 ?SESSION?,對于某個對象,MyBatis 將返回在本地緩存中唯一對象的引用。對返回的對象(例如 ?list?)做出的任何修改將會影響本地緩存的內(nèi)容,進(jìn)而將會影響到在本次 ?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)

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

我們已經(jīng)在之前的入門章節(jié)中見到過一個使用映射器的示例。一個映射器類就是一個僅需聲明與 ?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);
}

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

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

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

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

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

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

映射器注解

設(shè)計(jì)初期的 MyBatis 是一個 XML 驅(qū)動的框架。配置信息是基于 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 的配置會比 XML 有更大的選擇余地。雖說如此,基于 Java 注解的配置還是有它的好處的。

注解如下表所示:

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

映射注解示例

這個例子展示了如何使用 ?@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);

這個例子展示了如何使用 ?@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);

這個例子展示了如何使用 ?@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);

這個例子展示了如何使用單個參數(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();
  }
}

這個例子展示了如何使用多個參數(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();
  }
}

這個例子顯示使用全局配置(自 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)中,會將映射器方法的調(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();
  }
}

這個例子顯示語句注釋上的 ?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

公眾號
微信公眾號

編程獅公眾號