iBatis開發(fā)詳解(4)---select詳解

2018-10-13 11:35 更新

    <select>是iBatis已經(jīng)映射的語句類型,就是查詢了,為了配合說明,這里再介紹兩個標記:<sql>和<include>,前者用來創(chuàng)建一個文本片段,這些片段可以組合起來創(chuàng)建完整的SQL語句;后者很顯然就是包含的意思了。假設(shè)我們有如下代碼段: 

<sql id="select-user">  
    select * from users  
</sql>  
<sql id="select-count">  
    select count(*) as value from users  
</sql>  
<sql id="where-age-over-value">  
    <![CDATA[ 
        where age > #value:INT# 
    ]]>  
</sql>  
<select id="getUserAgeOver" resultClass="hashmap">  
    <include refid="select-user" />  
    <include refid="where-age-over-value" />  
</select>  
<select id="getUserCountAgeOver" resultClass="int">  
    <include refid="select-count" />  
    <include refid="where-age-over-value" />  
</select>  
   該部分代碼展示了sql和include的使用,其中使用了CDATA段,這是因為XML標簽本體中出現(xiàn)了于XML標簽沖突的字符,這很好理解。后面兩個查詢就是我們執(zhí)行的語句部分,程序代碼可以這么來寫: 
List users = sqlMap.queryForList("User.getUserAgeOver","23");  
System.out.println(users);  
int userCount = (Integer) sqlMap.queryForObject(  
    "User.getUserCountAgeOver", "22");  
System.out.println(userCount);  
   如果可以查詢到記錄,那么就會打印出來了。上面的例子中我們是用了#來標識傳遞的參數(shù),#被成為占位符,這是內(nèi)聯(lián)參數(shù)的傳遞方式的一種。
<select id="getUserById" resultClass="User">  
    select  
        userId,  
        userName,  
        password,  
        age,  
        mobile,  
        mail  
    from  
        users  
    where  
        userId = #value#  
</select>  
  在程序中,用下面這些代碼就能達到查詢效果了。
User user = (User) sqlMap.queryForObject("User.getUserById", new Integer(1));  
System.out.println(user);
    #value#是告訴iBatis傳遞一個簡單的參數(shù),iBatis處理該語句時,將會把#value#轉(zhuǎn)換為預(yù)處理參數(shù)形式,然后將這個參數(shù)的值設(shè)置為1(就是queryForObject()方法的第二個參數(shù)),之后執(zhí)行該預(yù)處理語句。最后iBatis接受返回的結(jié)果,然后把它映射到一個Java對象并返回該對象,這就是sqlMap的執(zhí)行過程。

 
    下面來看另外一種內(nèi)聯(lián)參數(shù)形式,就是使用$作為占位符。它可以直接把參數(shù)插入到SQL語句中,這在該SQL語句被轉(zhuǎn)變?yōu)閰?shù)化語句之前就執(zhí)行了。如此就會留下安全隱患,它可能給SQL注入有機可乘,而且過度使用還會有性能問題,看下面這個語句: 

<select id="getUserByLikeEmail" resultClass="User">  
    select  
        userId,  
        userName,  
        password,  
        age,  
        mobile,  
        email  
    from  
        users  
    where  
        email like '%$value$%'  
</select>  
   在程序中,我們可以使用如下代碼來執(zhí)行模糊查詢: 

List<User> users = sqlMap.queryForList("User.getUserByLikeEmail", "gmail"); 
System.out.println(users); 

    若要使用#方式來當占位符,那么模糊查詢時可能不是那么方便,需要如下進行:email like concat('%',#value#,'%'),這是MySQL的情況。所以模糊查詢使用$比較方便。 


    以上的查詢中我們使用了resultClass這種自動結(jié)果映射,這是iBatis的一種執(zhí)行機制,而我們也可以進行自定義結(jié)果映射,就是使用resultMap。如果我們在查詢中兩者都沒有使用的話,那么iBatis執(zhí)行查詢但是不能返回任何東西。 


    當我們使用bean作為結(jié)果映射時要注意如果結(jié)果列存在于數(shù)據(jù)庫而不存在于bean中,那么我們不會得到任何數(shù)據(jù),而且執(zhí)行不會報錯。自動映射使用起來很方便,但是更穩(wěn)健的要數(shù)外部結(jié)果映射了。 


    如果語句中的字段可變,那么可以使用動態(tài)結(jié)果映射,如: 

<select id="getUserByLikeEmail" resultClass="User" parameterClass="parameterMap">  
    select  
        userId,  
        userName,  
    <dynamic>  
        <isEqual property="includePassword" compareValue="true">  
            password,  
        </isEqual>  
    </dynamic>  
        age,  
        mobile,  
        email  
    from   
        users   
    where   
        email like concat('%',#email#,'%')  
</select>  
    程序中我們先定義一個ParameterMap類型,然后執(zhí)行查詢,如下: 
ParameterMap params = new ParameterMap("email", "gmail",  
        "includePassword", true);  
List users = sqlMap.queryForList("User.getUserByLikeEmail", params);  
System.out.println(users);  
    這樣我們就能人為控制password字段是輸出了。下面我們來看外部參數(shù)映射,使用外部參數(shù)映射主要是在XML中定義parameterMap,標識它的id和class后再在其中定義parameter,它包括如下屬性:property,javaType,jdbcType,nullValue,mode和typeHandler。要區(qū)分這和我們上面定義的ParameterMap類型是兩回事。我們定義的ParameterMap是如下定義的: 
package ibatis.util;  
import java.util.HashMap;  
public class ParameterMap extends HashMap<Object, Object> {  
    private static final long serialVersionUID = 1L;  
    public ParameterMap(Object... parameters) {  
        for (int i = 0; i < parameters.length - 1; i += 2) {  
            super.put(parameters[i], parameters[i + 1]);  
        }  
    }  
}  
    它是作為輔助類來用的,給SQL語句提供參數(shù),在配置文件中,我沒使用的是typeAlias來為它重命名的,而且在select標簽中我們使用的是parameterClass屬性,而不是parameterMap屬性,這里要區(qū)分開,它們可以說是完全不同的。 


    說完了外部參數(shù)映射,再說說外部結(jié)果映射。上面的例子中我們使用的映射有JavaBean形式的,也有hashmap形式的,但要注意我們是用的都是resultClass屬性來標識它們的,它們都屬于內(nèi)聯(lián)結(jié)果映射。外部結(jié)果映射是使用resultMap來定義的,我們來看一個實例,來更直觀的說明,首先定義一個resultMap的類型: 

package ibatis.util;  
public class PrimitiveResult {  
    private int userCount;  
    public int getUserCount() {  
        return userCount;  
    }  
    public void setUserCount(int userCount) {  
        this.userCount = userCount;  
    }  
    @Override  
    public String toString() {  
        return "PrimitiveResult [userCount=" + userCount + "]";  
    }  
}  
   很簡單的一個類型,就是描述用戶數(shù)量的。再在XML中定義這個類型: 
<resultMap class="ibatis.util.PrimitiveResult" id="primitiveResultMap">  
<result property="userCount" column="userCount" javaType="java.lang.Integer" jdbcType="int" />  
</resultMap>  
    這里說明一下property就是定義PrimitiveResult中的一個屬性名,這里是userCount,后面的column應(yīng)該是數(shù)據(jù)庫中的字段名,這里數(shù)據(jù)庫中沒有統(tǒng)計用戶數(shù)量這個字段,我們可以在SQL語句中使用as重命名來進行,javaType和jdbcType就好理解了,分別是Java對象的類型和數(shù)據(jù)庫字段的類型。 


    下面來看看查詢部分的定義: 

<select id="selectPrimitiveByUserId" resultMap="primitiveResultMap">  
    select  
        count(*) as userCount  
    from  
        users  
</select>  
   注意這里是resultMap就行了,不再是resultClass了,下面就是程序代碼了: 
PrimitiveResult userCount = (PrimitiveResult) sqlMap.queryForObject(  
            "User.selectPrimitiveByUserId");  
System.out.println(userCount);  
    為我們之前在PrimitiveResult中覆蓋了toString()方法,那么我們執(zhí)行程序,就得到了:PrimitiveResult [userCount=2],這就是外部結(jié)果映射的使用了。 


    最后我們來比較一下javabean的結(jié)果映射和map結(jié)果映射。Javabean形式的映射都是我們手寫的bean類,而map就直接使用,是內(nèi)聯(lián)情況的。它們各有好處也有缺點。比如使用javabean那么性能很好,而且是強類型檢測,缺點是很多的get/set方法。而用map不需要很多代碼,但它的效率就慢了,沒有強類型的檢測。 

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號