正如之前所提到的,?SqlSession
?在 MyBatis 中是非常強(qiáng)大的一個(gè)類。它包含了所有執(zhí)行語句、提交或回滾事務(wù)以及獲取映射器實(shí)例的方法。
?SqlSession
?類的方法超過了 20 個(gè),為了方便理解,我們將它們分成幾種組別。
這些方法被用來執(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ì)被緩存。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()
有四個(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()
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 、eviction 、flushInterval 、size 、readWrite 、blocking 、properties 。 |
@Property
|
N/A | <property>
|
指定參數(shù)值或占位符(placeholder)(該占位符能被 mybatis-config.xml 內(nèi)的配置屬性替換)。屬性:name 、value 。(僅在 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 |
|
ConstructorArgs 集合的一部分,代表一個(gè)構(gòu)造方法參數(shù)。屬性:id 、column 、javaType 、jdbcType 、typeHandler 、select 、resultMap 。id 屬性和 XML 元素 <idArg> 相似,它是一個(gè)布爾值,表示該屬性是否用于唯一標(biāo)識(shí)和比較對象。從版本
3.5.4 開始,該注解變?yōu)榭芍貜?fù)注解。 |
@TypeDiscriminator
|
方法
|
<discriminator>
|
決定使用何種結(jié)果映射的一組取值(case)。屬性:column 、javaType 、jdbcType 、typeHandler 、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 |
|
在列和屬性或字段之間的單個(gè)結(jié)果映射。屬性:id 、column 、javaType 、jdbcType 、typeHandler 、one 、many 。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.DEFAULT 、resultSetType=DEFAULT 、statementType=PREPARED 、fetchSize=-1 、timeout=-1 、useGeneratedKeys=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é)。 |
|
方法
|
|
每個(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 ?,后者將被丟棄。 |
|
方法
|
|
允許構(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 、type 、method 、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 則用于選擇語句類型,可以選擇 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 | 這個(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();
更多建議: