MyBatis中XML 映射文件中常見(jiàn)的標(biāo)簽說(shuō)明
SQL 映射文件只有很少的幾個(gè)頂級(jí)元素(按照應(yīng)被定義的順序列出):
- cache – 對(duì)給定命名空間的緩存配置。
- cache-ref – 對(duì)其他命名空間緩存配置的引用。
- resultMap – 是最復(fù)雜也是最強(qiáng)大的元素,用來(lái)描述如何從數(shù)據(jù)庫(kù)結(jié)果集中來(lái)加載對(duì)象。
- parameterMap – 已被廢棄!老式風(fēng)格的參數(shù)映射。更好的辦法是使用內(nèi)聯(lián)參數(shù),此元素可能在將來(lái)被移除。
- sql – 可被其他語(yǔ)句引用的可重用語(yǔ)句塊。
- insert – 映射插入語(yǔ)句
- update – 映射更新語(yǔ)句
- delete – 映射刪除語(yǔ)句
- select – 映射查詢語(yǔ)句
select
<select id="selectPerson" parameterType="int" resultType="hashmap"> SELECT * FROM PERSON WHERE ID = #{id} </select>
這個(gè)語(yǔ)句被稱作 selectPerson,接受一個(gè) int(或 Integer)類型的參數(shù),并返回一個(gè) HashMap 類型的對(duì)象,其中的鍵是列名,值便是結(jié)果行中的對(duì)應(yīng)值。
注意參數(shù)符號(hào):#{id}
這就告訴 MyBatis 創(chuàng)建一個(gè)預(yù)處理語(yǔ)句(PreparedStatement)參數(shù),在 JDBC 中,這樣的一個(gè)參數(shù)在 SQL 中會(huì)由一個(gè)“?”來(lái)標(biāo)識(shí),并被傳遞到一個(gè)新的預(yù)處理語(yǔ)句中,就像這樣:
// 近似的 JDBC 代碼,非 MyBatis 代碼... String selectPerson = "SELECT * FROM PERSON WHERE ID=?"; PreparedStatement ps = conn.prepareStatement(selectPerson); ps.setInt(1,id); <select id="selectPerson" parameterType="int" parameterMap="deprecated" resultType="hashmap" resultMap="personResultMap" flushCache="false" useCache="true" timeout="10" fetchSize="256" statementType="PREPARED" resultSetType="FORWARD_ONLY">
屬性 | 描述 |
---|---|
id | 在命名空間中唯一的標(biāo)識(shí)符,可以被用來(lái)引用這條語(yǔ)句。 |
parameterType | 將會(huì)傳入這條語(yǔ)句的參數(shù)類的完全限定名或別名。這個(gè)屬性是可選的,因?yàn)?MyBatis 可以通過(guò)類型處理器(TypeHandler) 推斷出具體傳入語(yǔ)句的參數(shù),默認(rèn)值為未設(shè)置(unset)。 |
parameterMap | 這是引用外部 parameterMap 的已經(jīng)被廢棄的方法。請(qǐng)使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性。 |
resultType | 從這條語(yǔ)句中返回的期望類型的類的完全限定名或別名。 注意如果返回的是集合,那應(yīng)該設(shè)置為集合包含的類型,而不是集合本身??梢允褂?resultType 或 resultMap,但不能同時(shí)使用。 |
resultMap | 外部 resultMap 的命名引用。結(jié)果集的映射是 MyBatis 最強(qiáng)大的特性,如果你對(duì)其理解透徹,許多復(fù)雜映射的情形都能迎刃而解??梢允褂?resultMap 或 resultType,但不能同時(shí)使用。 |
flushCache | 將其設(shè)置為 true 后,只要語(yǔ)句被調(diào)用,都會(huì)導(dǎo)致本地緩存和二級(jí)緩存被清空,默認(rèn)值:false。 |
useCache | 將其設(shè)置為 true 后,將會(huì)導(dǎo)致本條語(yǔ)句的結(jié)果被二級(jí)緩存緩存起來(lái),默認(rèn)值:對(duì) select 元素為 true。 |
timeout | 這個(gè)設(shè)置是在拋出異常之前,驅(qū)動(dòng)程序等待數(shù)據(jù)庫(kù)返回請(qǐng)求結(jié)果的秒數(shù)。默認(rèn)值為未設(shè)置(unset)(依賴驅(qū)動(dòng))。 |
fetchSize | 這是一個(gè)給驅(qū)動(dòng)的提示,嘗試讓驅(qū)動(dòng)程序每次批量返回的結(jié)果行數(shù)和這個(gè)設(shè)置值相等。 默認(rèn)值為未設(shè)置(unset)(依賴驅(qū)動(dòng))。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 中的一個(gè)。這會(huì)讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認(rèn)值:PREPARED。 |
resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等價(jià)于 unset) 中的一個(gè),默認(rèn)值為 unset (依賴驅(qū)動(dòng))。 |
databaseId | 如果配置了數(shù)據(jù)庫(kù)廠商標(biāo)識(shí)(databaseIdProvider),MyBatis 會(huì)加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語(yǔ)句;如果帶或者不帶的語(yǔ)句都有,則不帶的會(huì)被忽略。 |
resultOrdered | 這個(gè)設(shè)置僅針對(duì)嵌套結(jié)果 select 語(yǔ)句適用:如果為 true,就是假設(shè)包含了嵌套結(jié)果集或是分組,這樣的話當(dāng)返回一個(gè)主結(jié)果行的時(shí)候,就不會(huì)發(fā)生有對(duì)前面結(jié)果集的引用的情況。 這就使得在獲取嵌套的結(jié)果集的時(shí)候不至于導(dǎo)致內(nèi)存不夠用。默認(rèn)值:false。 |
resultSets | 這個(gè)設(shè)置僅對(duì)多結(jié)果集的情況適用。它將列出語(yǔ)句執(zhí)行后返回的結(jié)果集并給每個(gè)結(jié)果集一個(gè)名稱,名稱是逗號(hào)分隔的。 |
insert, update 和 delete
數(shù)據(jù)變更語(yǔ)句 insert,update 和 delete 的實(shí)現(xiàn)非常接近:
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20"> <update id="updateAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20"> <delete id="deleteAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20">
屬性 | 描述 |
---|---|
id | 命名空間中的唯一標(biāo)識(shí)符,可被用來(lái)代表這條語(yǔ)句。 |
parameterType | 將要傳入語(yǔ)句的參數(shù)的完全限定類名或別名。這個(gè)屬性是可選的,因?yàn)?MyBatis 可以通過(guò)類型處理器推斷出具體傳入語(yǔ)句的參數(shù),默認(rèn)值為未設(shè)置(unset)。 |
parameterMap | 這是引用外部 parameterMap 的已經(jīng)被廢棄的方法。請(qǐng)使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性。 |
flushCache | 將其設(shè)置為 true 后,只要語(yǔ)句被調(diào)用,都會(huì)導(dǎo)致本地緩存和二級(jí)緩存被清空,默認(rèn)值:true(對(duì)于 insert、update 和 delete 語(yǔ)句)。 |
timeout | 這個(gè)設(shè)置是在拋出異常之前,驅(qū)動(dòng)程序等待數(shù)據(jù)庫(kù)返回請(qǐng)求結(jié)果的秒數(shù)。默認(rèn)值為未設(shè)置(unset)(依賴驅(qū)動(dòng))。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 的一個(gè)。這會(huì)讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認(rèn)值:PREPARED。 |
useGeneratedKeys | (僅對(duì) insert 和 update 有用)這會(huì)令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來(lái)取出由數(shù)據(jù)庫(kù)內(nèi)部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)的自動(dòng)遞增字段),默認(rèn)值:false。 |
keyProperty | (僅對(duì) insert 和 update 有用)唯一標(biāo)記一個(gè)屬性,MyBatis 會(huì)通過(guò) getGeneratedKeys 的返回值或者通過(guò) insert 語(yǔ)句的 selectKey 子元素設(shè)置它的鍵值,默認(rèn)值:未設(shè)置(unset)。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱列表。 |
keyColumn | (僅對(duì) insert 和 update 有用)通過(guò)生成的鍵值設(shè)置表中的列名,這個(gè)設(shè)置僅在某些數(shù)據(jù)庫(kù)(像 PostgreSQL)是必須的,當(dāng)主鍵列不是表中的第一列的時(shí)候需要設(shè)置。如果希望使用多個(gè)生成的列,也可以設(shè)置為逗號(hào)分隔的屬性名稱列表。 |
databaseId | 如果配置了數(shù)據(jù)庫(kù)廠商標(biāo)識(shí)(databaseIdProvider),MyBatis 會(huì)加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語(yǔ)句;如果帶或者不帶的語(yǔ)句都有,則不帶的會(huì)被忽略。 |
生成主鍵
<selectKey keyProperty="id" resultType="int" order="BEFORE" statementType="PREPARED">
屬性 | 描述 |
---|---|
keyProperty | selectKey 語(yǔ)句結(jié)果應(yīng)該被設(shè)置的目標(biāo)屬性。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱列表。 |
keyColumn | 匹配屬性的返回結(jié)果集中的列名稱。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱列表。 |
resultType | 結(jié)果的類型。MyBatis 通??梢酝茢喑鰜?lái),但是為了更加精確,寫(xiě)上也不會(huì)有什么問(wèn)題。MyBatis 允許將任何簡(jiǎn)單類型用作主鍵的類型,包括字符串。如果希望作用于多個(gè)生成的列,則可以使用一個(gè)包含期望屬性的 Object 或一個(gè) Map。 |
order | 這可以被設(shè)置為 BEFORE 或 AFTER。如果設(shè)置為 BEFORE,那么它會(huì)首先生成主鍵,設(shè)置 keyProperty 然后執(zhí)行插入語(yǔ)句。如果設(shè)置為 AFTER,那么先執(zhí)行插入語(yǔ)句,然后是 selectKey 中的語(yǔ)句 - 這和 Oracle 數(shù)據(jù)庫(kù)的行為相似,在插入語(yǔ)句內(nèi)部可能有嵌入索引調(diào)用。 |
statementType | 與前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 語(yǔ)句的映射類型,分別代表 PreparedStatement 和 CallableStatement 類型。 |
<selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id"> SELECT LAST_INSERT_ID() AS id </selectKey>
sql
這個(gè)元素可以被用來(lái)定義可重用的 SQL 代碼段,這些 SQL 代碼可以被包含在其他語(yǔ)句中。它可以(在加載的時(shí)候)被靜態(tài)地設(shè)置參數(shù)。 在不同的包含語(yǔ)句中可以設(shè)置不同的值到參數(shù)占位符上。比如:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql> <select id="selectUsers" resultType="map"> select <include refid="userColumns"><property name="alias" value="t1"/></include>, <include refid="userColumns"><property name="alias" value="t2"/></include> from some_table t1 cross join some_table t2 </select>
結(jié)果映射
resultMap 元素是 MyBatis 中最重要最強(qiáng)大的元素,在一些情形下允許你進(jìn)行一些 JDBC 不支持的操作。實(shí)際上,在為一些比如連接的復(fù)雜語(yǔ)句編寫(xiě)映射代碼的時(shí)候,一份 resultMap 能夠代替實(shí)現(xiàn)同等功能的長(zhǎng)達(dá)數(shù)千行的代碼。ResultMap 的設(shè)計(jì)思想是,對(duì)于簡(jiǎn)單的語(yǔ)句根本不需要配置顯式的結(jié)果映射,而對(duì)于復(fù)雜一點(diǎn)的語(yǔ)句只需要描述它們的關(guān)系就行了。
在JavaBean中定義一個(gè)有 3 個(gè)屬性:id,username 和 hashedPassword的類,然后在mapper.xml中,這些屬性會(huì)對(duì)應(yīng)到 select 語(yǔ)句中的列名,這樣的一個(gè) JavaBean 可以被映射到 ResultSet,就像映射到 HashMap 一樣簡(jiǎn)單。
<select id="selectUsers" resultType="com.someapp.model.User"> select id, username, hashedPassword from some_table where id = #{id} </select>
像第三中的第三個(gè)例子,也可以定義外部resultMap,這也是解決列名不匹配的另外一種方式。
<resultMap id="userResultMap" type="User"> <id property="id" column="user_id" /> <result property="username" column="user_name"/> <result property="password" column="hashed_password"/> </resultMap> <select id="selectUsers" resultMap="userResultMap"> select user_id, user_name, hashed_password from some_table where id = #{id} </select>
結(jié)果映射(resultMap)
- constructor-用于在實(shí)例化類時(shí),注入結(jié)果到構(gòu)造方法中
- idArg - ID 參數(shù);標(biāo)記出作為 ID 的結(jié)果可以幫助提高整體性能
- arg - 將被注入到構(gòu)造方法的一個(gè)普通結(jié)果
- id – 一個(gè) ID 結(jié)果;標(biāo)記出作為 ID 的結(jié)果可以幫助提高整體性能
- result – 注入到字段或 JavaBean 屬性的普通結(jié)果
- association– 一個(gè)復(fù)雜類型的關(guān)聯(lián);許多結(jié)果將包裝成這種類型
- 嵌套結(jié)果映射 – 關(guān)聯(lián)本身可以是一個(gè) resultMap 元素,或者從別處引用一個(gè)
- collection– 一個(gè)復(fù)雜類型的集合
- 嵌套結(jié)果映射 – 集合本身可以是一個(gè) resultMap 元素,或者從別處引用一個(gè)
- discriminator– 使用結(jié)果值來(lái)決定使用哪個(gè)resultMap
- case– 基于某些值的結(jié)果映射
- 嵌套結(jié)果映射 – case 本身可以是一個(gè) resultMap 元素,因此可以具有相同的結(jié)構(gòu)和元素,或者從別處引用一個(gè)。
屬性 | 描述 |
---|---|
id | 當(dāng)前命名空間中的一個(gè)唯一標(biāo)識(shí),用于標(biāo)識(shí)一個(gè)結(jié)果映射。 |
type | 類的完全限定名, 或者一個(gè)類型別名(關(guān)于內(nèi)置的類型別名,可以參考上面的表格)。 |
autoMapping | 如果設(shè)置這個(gè)屬性,MyBatis將會(huì)為本結(jié)果映射開(kāi)啟或者關(guān)閉自動(dòng)映射。 這個(gè)屬性會(huì)覆蓋全局的屬性 autoMappingBehavior。默認(rèn)值:未設(shè)置(unset)。 |
id & result
<id property="id" column="post_id"/> <result property="subject" column="post_subject"/>
這些是結(jié)果映射最基本的內(nèi)容。id 和 result 元素都將一個(gè)列的值映射到一個(gè)簡(jiǎn)單數(shù)據(jù)類型(String, int, double, Date 等)的屬性或字段。
這兩者之間的唯一不同是,id 元素表示的結(jié)果將是對(duì)象的標(biāo)識(shí)屬性,這會(huì)在比較對(duì)象實(shí)例時(shí)用到。 這樣可以提高整體的性能,尤其是進(jìn)行緩存和嵌套結(jié)果映射(也就是連接映射)的時(shí)候。
屬性 | 描述 |
---|---|
property | 映射到列結(jié)果的字段或?qū)傩?。如果用?lái)匹配的 JavaBean 存在給定名字的屬性,那么它將會(huì)被使用。否則 MyBatis 將會(huì)尋找給定名稱的字段。 無(wú)論是哪一種情形,你都可以使用通常的點(diǎn)式分隔形式進(jìn)行復(fù)雜屬性導(dǎo)航。 比如,你可以這樣映射一些簡(jiǎn)單的東西:“username”,或者映射到一些復(fù)雜的東西上:“address.street.number”。 |
column | 數(shù)據(jù)庫(kù)中的列名,或者是列的別名。一般情況下,這和傳遞給 resultSet.getString(columnName) 方法的參數(shù)一樣。 |
javaType | 一個(gè) Java 類的完全限定名,或一個(gè)類型別名(關(guān)于內(nèi)置的類型別名,可以參考上面的表格)。 如果你映射到一個(gè) JavaBean,MyBatis 通常可以推斷類型。然而,如果你映射到的是 HashMap,那么你應(yīng)該明確地指定 javaType 來(lái)保證行為與期望的相一致。 |
jdbcType | JDBC 類型,所支持的 JDBC 類型參見(jiàn)這個(gè)表格之后的“支持的 JDBC 類型”。 只需要在可能執(zhí)行插入、更新和刪除的且允許空值的列上指定 JDBC 類型。這是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 編程,你需要對(duì)可能存在空值的列指定這個(gè)類型。 |
typeHandler | 我們?cè)谇懊嬗懻撨^(guò)默認(rèn)的類型處理器。使用這個(gè)屬性,你可以覆蓋默認(rèn)的類型處理器。 這個(gè)屬性值是一個(gè)類型處理器實(shí)現(xiàn)類的完全限定名,或者是類型別名。 |
緩存
默認(rèn)情況下,只啟用了本地的會(huì)話緩存,它僅僅對(duì)一個(gè)會(huì)話中的數(shù)據(jù)進(jìn)行緩存。 要啟用全局的二級(jí)緩存,只需要在你的 SQL 映射文件中添加一行:<cache/>
基本上就是這樣。這個(gè)簡(jiǎn)單語(yǔ)句的效果如下:
- 映射語(yǔ)句文件中的所有 select 語(yǔ)句的結(jié)果將會(huì)被緩存。
- 映射語(yǔ)句文件中的所有 insert、update 和 delete 語(yǔ)句會(huì)刷新緩存。
- 緩存會(huì)使用最近最少使用算法(LRU, Least Recently Used)算法來(lái)清除不需要的緩存。
- 緩存不會(huì)定時(shí)進(jìn)行刷新(也就是說(shuō),沒(méi)有刷新間隔)。
- 緩存會(huì)保存列表或?qū)ο螅o(wú)論查詢方法返回哪種)的 1024 個(gè)引用。
- 緩存會(huì)被視為讀/寫(xiě)緩存,這意味著獲取到的對(duì)象并不是共享的,可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。
提示 緩存只作用于 cache 標(biāo)簽所在的映射文件中的語(yǔ)句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的語(yǔ)句將不會(huì)被默認(rèn)緩存。你需要使用 @CacheNamespaceRef 注解指定緩存作用域。
這些屬性可以通過(guò) cache 元素的屬性來(lái)修改。比如:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
這個(gè)更高級(jí)的配置創(chuàng)建了一個(gè) FIFO 緩存,每隔 60 秒刷新,最多可以存儲(chǔ)結(jié)果對(duì)象或列表的 512 個(gè)引用,而且返回的對(duì)象被認(rèn)為是只讀的,因此對(duì)它們進(jìn)行修改可能會(huì)在不同線程中的調(diào)用者產(chǎn)生沖突。
可用的清除策略有:
- LRU – 最近最少使用:移除最長(zhǎng)時(shí)間不被使用的對(duì)象。
- FIFO – 先進(jìn)先出:按對(duì)象進(jìn)入緩存的順序來(lái)移除它們。
- SOFT – 軟引用:基于垃圾回收器狀態(tài)和軟引用規(guī)則移除對(duì)象。
- WEAK – 弱引用:更積極地基于垃圾收集器狀態(tài)和弱引用規(guī)則移除對(duì)象。
默認(rèn)的清除策略是 LRU。
flushInterval(刷新間隔)屬性可以被設(shè)置為任意的正整數(shù),設(shè)置的值應(yīng)該是一個(gè)以毫秒為單位的合理時(shí)間量。 默認(rèn)情況是不設(shè)置,也就是沒(méi)有刷新間隔,緩存僅僅會(huì)在調(diào)用語(yǔ)句時(shí)刷新。
size(引用數(shù)目)屬性可以被設(shè)置為任意正整數(shù),要注意欲緩存對(duì)象的大小和運(yùn)行環(huán)境中可用的內(nèi)存資源。默認(rèn)值是 1024。
readOnly(只讀)屬性可以被設(shè)置為 true 或 false。只讀的緩存會(huì)給所有調(diào)用者返回緩存對(duì)象的相同實(shí)例。 因此這些對(duì)象不能被修改。這就提供了可觀的性能提升。而可讀寫(xiě)的緩存會(huì)(通過(guò)序列化)返回緩存對(duì)象的拷貝。 速度上會(huì)慢一些,但是更安全,因此默認(rèn)值是 false。
提示 二級(jí)緩存是事務(wù)性的。這意味著,當(dāng) SqlSession 完成并提交時(shí),或是完成并回滾,但沒(méi)有執(zhí)行 flushCache=true 的 insert/delete/update 語(yǔ)句時(shí),緩存會(huì)獲得更新。
使用自定義緩存
除了上述自定義緩存的方式,你也可以通過(guò)實(shí)現(xiàn)你自己的緩存,或?yàn)槠渌谌骄彺娣桨竸?chuàng)建適配器,來(lái)完全覆蓋緩存行為。
<cache type="com.domain.something.MyCustomCache"/>
例子:
type 屬性指定的類必須實(shí)現(xiàn) org.mybatis.cache.Cache 接口,且提供一個(gè)接受 String 參數(shù)作為 id 的構(gòu)造器。 這個(gè)接口是 MyBatis 框架中許多復(fù)雜的接口之一,但是行為卻非常簡(jiǎn)單。
public interface Cache { String getId(); int getSize(); void putObject(Object key, Object value); Object getObject(Object key); boolean hasKey(Object key); Object removeObject(Object key); void clear(); }
動(dòng)態(tài)SQL
- Mybatis 動(dòng)態(tài) SQL ,可以讓我們?cè)?XML 映射文件內(nèi),以 XML 標(biāo)簽的形式編寫(xiě)動(dòng)態(tài) SQL ,完成邏輯判斷和動(dòng)態(tài)拼接 SQL 的功能。
- Mybatis 提供了 9 種動(dòng)態(tài) SQL 標(biāo)簽:<if />、<choose />、<when />、<otherwise />、<trim />、<where />、<set />、<foreach />、<bind /> 。
- 其執(zhí)行原理為,使用 OGNL 的表達(dá)式,從 SQL 參數(shù)對(duì)象中計(jì)算表達(dá)式的值,根據(jù)表達(dá)式的值動(dòng)態(tài)拼接 SQL ,以此來(lái)完成動(dòng)態(tài) SQL 的功能。
if
動(dòng)態(tài) SQL 通常要做的事情是根據(jù)條件包含 where 子句的一部分。比如:
<select id="findActiveBlogWithTitleLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE' <if test="title != null"> AND title like #{title} </if> </select>
這條語(yǔ)句提供了一種可選的查找文本功能。如果沒(méi)有傳入“title”,那么所有處于“ACTIVE”狀態(tài)的BLOG都會(huì)返回;反之若傳入了“title”,那么就會(huì)對(duì)“title”一列進(jìn)行模糊查找并返回 BLOG 結(jié)果(“title”參數(shù)值是可以包含一些掩碼或通配符的)。
通過(guò)“title”和“author”兩個(gè)參數(shù)進(jìn)行可選搜索:
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE' <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </select>
choose, when, otherwise
有時(shí)我們不想應(yīng)用到所有的條件語(yǔ)句,而只想從中擇其一項(xiàng)。針對(duì)這種情況,MyBatis 提供了 choose 元素,它有點(diǎn)像 Java 中的 switch 語(yǔ)句。
這次變?yōu)樘峁┝恕皌itle”就按“title”查找,提供了“author”就按“author”查找的情形,若兩者都沒(méi)有提供,就返回所有符合條件的 BLOG(實(shí)際情況可能是由管理員按一定策略選出 BLOG 列表,而不是返回大量無(wú)意義的隨機(jī)結(jié)果)。
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE' <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
trim, where, set
上面的幾個(gè)例子,如果條件不滿足的話,會(huì)拼湊成不成一條sql語(yǔ)句,導(dǎo)致無(wú)法查詢,如:SELECT * FROM BLOG WHERE
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG <where> <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where> </select>
where 元素只會(huì)在至少有一個(gè)子元素的條件返回 SQL 子句的情況下才去插入“WHERE”子句。而且,若語(yǔ)句的開(kāi)頭為“AND”或“OR”,where 元素也會(huì)將它們?nèi)コ?/p>
如果 where 元素沒(méi)有按正常套路出牌,我們可以通過(guò)自定義 trim 元素來(lái)定制 where 元素的功能。比如,和 where 元素等價(jià)的自定義 trim 元素為:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
prefixOverrides 屬性會(huì)忽略通過(guò)管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 屬性中的內(nèi)容,并且插入 prefix 屬性中指定的內(nèi)容。
類似的用于動(dòng)態(tài)更新語(yǔ)句的解決方案叫做 set。set 元素可以用于動(dòng)態(tài)包含需要更新的列,而舍去其它的。比如:
<update id="updateAuthorIfNecessary"> update Author <set> <if test="username != null">username=#{username},</if> <if test="password != null">password=#{password},</if> <if test="email != null">email=#{email},</if> <if test="bio != null">bio=#{bio}</if> </set> where id=#{id} </update>
這里,set 元素會(huì)動(dòng)態(tài)前置 SET 關(guān)鍵字,同時(shí)也會(huì)刪掉無(wú)關(guān)的逗號(hào),因?yàn)橛昧藯l件語(yǔ)句之后很可能就會(huì)在生成的 SQL 語(yǔ)句的后面留下這些逗號(hào)。(譯者注:因?yàn)橛玫氖恰癷f”元素,若最后一個(gè)“if”沒(méi)有匹配上而前面的匹配上,SQL 語(yǔ)句的最后就會(huì)有一個(gè)逗號(hào)遺留)
若你對(duì) set 元素等價(jià)的自定義 trim 元素的代碼感興趣,那這就是它的真面目:
<trim prefix="SET" suffixOverrides=","> ... </trim>
注意這里我們刪去的是后綴值,同時(shí)添加了前綴值。
foreach
動(dòng)態(tài) SQL 的另外一個(gè)常用的操作需求是對(duì)一個(gè)集合進(jìn)行遍歷,通常是在構(gòu)建 IN 條件語(yǔ)句的時(shí)候。比如:
<select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>
foreach 元素的功能非常強(qiáng)大,它允許你指定一個(gè)集合,聲明可以在元素體內(nèi)使用的集合項(xiàng)(item)和索引(index)變量。它也允許你指定開(kāi)頭與結(jié)尾的字符串以及在迭代結(jié)果之間放置分隔符。這個(gè)元素是很智能的,因此它不會(huì)偶然地附加多余的分隔符。
注意
可以將任何可迭代對(duì)象(如 List、Set 等)、Map 對(duì)象或者數(shù)組對(duì)象傳遞給 foreach 作為集合參數(shù)。當(dāng)使用可迭代對(duì)象或者數(shù)組時(shí),index 是當(dāng)前迭代的次數(shù),item 的值是本次迭代獲取的元素。當(dāng)使用 Map 對(duì)象(或者 Map.Entry 對(duì)象的集合)時(shí),index 是鍵,item 是值。
bind
bind 元素可以從 OGNL 表達(dá)式中創(chuàng)建一個(gè)變量并將其綁定到上下文。比如:
<select id="selectBlogsLike" resultType="Blog"> <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" /> SELECT * FROM BLOG WHERE title LIKE #{pattern} </select>
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring MVC接受表單自動(dòng)封裝特性實(shí)例解析
這篇文章主要介紹了Spring MVC接受表單自動(dòng)封裝特性實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02解決啟用 Spring-Cloud-OpenFeign 配置可刷新項(xiàng)目無(wú)法啟動(dòng)的問(wèn)題
這篇文章主要介紹了解決啟用 Spring-Cloud-OpenFeign 配置可刷新項(xiàng)目無(wú)法啟動(dòng)的問(wèn)題,本文重點(diǎn)給大家介紹Spring-Cloud-OpenFeign的原理及問(wèn)題解決方法,需要的朋友可以參考下2021-10-10Spring的@PreAuthorize注解自定義權(quán)限校驗(yàn)詳解
這篇文章主要介紹了Spring的@PreAuthorize注解自定義權(quán)限校驗(yàn)詳解,由于項(xiàng)目中,需要對(duì)外開(kāi)放接口,要求做請(qǐng)求頭校驗(yàn),不做其他權(quán)限控制,所以準(zhǔn)備對(duì)開(kāi)放的接口全部放行,不做登錄校驗(yàn),需要的朋友可以參考下2023-11-11使用Eclipse開(kāi)發(fā)工具如何解決Java Compiler中Annotation Processin不出現(xiàn)的問(wèn)題
這篇文章主要介紹了使用Eclipse開(kāi)發(fā)工具如何解決Java Compiler中Annotation Processin不出現(xiàn)的相關(guān)資料,需要的朋友可以參考下2015-11-11Java利用jenkins做項(xiàng)目的自動(dòng)化部署
這篇文章主要介紹了Java利用jenkins做項(xiàng)目的自動(dòng)化部署,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Java實(shí)現(xiàn)樹(shù)形結(jié)構(gòu)的示例代碼
由于業(yè)務(wù)需要,后端需要返回一個(gè)樹(shù)型結(jié)構(gòu)給前端,包含父子節(jié)點(diǎn)的數(shù)據(jù)已經(jīng)在數(shù)據(jù)庫(kù)中存儲(chǔ)好。本文將為大家分享Java現(xiàn)樹(shù)形結(jié)構(gòu)的示例代碼,需要的可以參考下2022-05-05淺談Java?abstract關(guān)鍵字不能和哪些關(guān)鍵字共存
本文主要介紹了Java?abstract關(guān)鍵字不能和哪些關(guān)鍵字共存,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-10-10java優(yōu)化hibernate性能的幾點(diǎn)建議
以上是在進(jìn)行struts+hibernate+spring進(jìn)行項(xiàng)目開(kāi)發(fā)中,對(duì)hibernate性能優(yōu)化的幾點(diǎn)心得。2008-10-10