MyBatis之Mapper XML 文件詳解(二)-sql和入參

sql


這個元素可以被用來定義可重用的 SQL 代碼段,可以包含在其他語句中。它可以被靜態地(在加載參數) 參數化. 不同的屬性值通過包含的實例變化. 比如:

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>

這個 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>

屬性值可以用於包含的refid屬性或者包含的字句裏面的屬性值,例如:

<sql id="sometable">
 ${prefix}Table
</sql>

<sql id="someinclude">
 from
   <include refid="${include_target}"/>
</sql>

<select id="select" resultType="map">
 select
   field1, field2, field3
 <include refid="someinclude">
   <property name="prefix" value="Some"/>
   <property name="include_target" value="sometable"/>
 </include>
</select>


參數(Parameters)


前面的所有語句中你所見到的都是簡單參數的例子,實際上參數是 MyBatis 非常強大的元素,對於簡單的做法,大概 90% 的情況參數都很少,比如:

<select id="selectUsers" resultType="User">
 select id, username, password
 from users
 where id = #{id}
</select>

上面的這個示例說明了一個非常簡單的命名參數映射。參數類型被設置爲 int,這樣這個參數就可以被設置成任何內容。原生的類型或簡單數據類型(比如整型和字符串)因爲沒有相關屬性,它會完全用參數值來替代。然而,如果傳入一個複雜的對象,行爲就會有一點不同了。比如:

<insert id="insertUser" parameterType="User">
 insert into users (id, username, password)
 values (#{id}, #{username}, #{password})
</insert>

如果 User 類型的參數對象傳遞到了語句中,id、username 和 password 屬性將會被查找,然後將它們的值傳入預處理語句的參數中。 


這點對於向語句中傳參是比較好的而且又簡單,不過參數映射的功能遠不止於此。 
首先,像 MyBatis 的其他部分一樣,參數也可以指定一個特殊的數據類型。

#{property,javaType=int,jdbcType=NUMERIC}

像 MyBatis 的剩餘部分一樣,javaType 通常可以從參數對象中來去確定,前提是隻要對象不是一個 HashMap。那麼 javaType 應該被確定來保證使用正確類型處理器。 


如果 null 被當作值來傳遞,對於所有可能爲空的列,JDBC Type 是需要的。你可以自己通過閱讀預處理語句的 setNull() 方法的 JavaDocs 文檔來研究這種情況。 


爲了以後定製類型處理方式,你也可以指定一個特殊的類型處理器類(或別名),比如:

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

儘管看起來配置變得越來越繁瑣,但實際上是很少去設置它們。 
對於數值類型,還有一個小數保留位數的設置,來確定小數點後保留的位數。

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

最後,mode 屬性允許你指定 IN,OUT 或 INOUT 參數。如果參數爲 OUT 或 INOUT,參數對象屬性的真實值將會被改變,就像你在獲取輸出參數時所期望的那樣。如果 mode 爲 OUT(或 INOUT),而且 jdbcType 爲 CURSOR(也就是 Oracle 的 REFCURSOR),你必須指定一個 resultMap 來映射結果集到參數類型。要注意這裏的 javaType 屬性是可選的,如果左邊的空白是 jdbcType 的 CURSOR 類型,它會自動地被設置爲結果集。

#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

MyBatis 也支持很多高級的數據類型,比如結構體,但是當註冊 out 參數時你必須告訴它語句類型名稱。比如(再次提示,在實際中要像這樣不能換行):

#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

儘管所有這些強大的選項很多時候你只簡單指定屬性名,其他的事情 MyBatis 會自己去推斷,最多你需要爲可能爲空的列名指定 jdbcType。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}

字符串替換 
默認情況下,使用#{}格式的語法會導致 MyBatis 創建預處理語句屬性並安全地設置值(比如?)。這樣做更安全,更迅速,通常也是首選做法,不過有時你只是想直接在 SQL 語句中插入一個不改變的字符串。比如,像 ORDER BY,你可以這樣來使用:

ORDER BY ${columnName}

這裏 MyBatis 不會修改或轉義字符串。 

 以這種方式接受從用戶輸出的內容並提供給語句中不變的字符串是不安全的,會導致潛在的 SQL 注入***,因此要麼不允許用戶輸入這些字段,要麼自行轉義並檢驗。

關注微信公主號:IT哈哈(it_haha),學習更多內容。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章