iBatis查詢select詳解

<select>是iBatis已經映射的語句類型,就是查詢了,爲了配合說明,這裏再介紹兩個標記:<sql>和<include>,前者用來創建一個文本片段,這些片段可以組合起來創建完整的SQL語句;後者很顯然就是包含的意思了。假設我們有如下代碼段: 
Xml代碼  收藏代碼
  1. <sql id="select-user">  
  2.     select * from users  
  3. </sql>  
  4. <sql id="select-count">  
  5.     select count(*) as value from users  
  6. </sql>  
  7. <sql id="where-age-over-value">  
  8.     <![CDATA[ 
  9.         where age > #value:INT# 
  10.     ]]>  
  11. </sql>  
  12. <select id="getUserAgeOver" resultClass="hashmap">  
  13.     <include refid="select-user" />  
  14.     <include refid="where-age-over-value" />  
  15. </select>  
  16. <select id="getUserCountAgeOver" resultClass="int">  
  17.     <include refid="select-count" />  
  18.     <include refid="where-age-over-value" />  
  19. </select>  

    該部分代碼展示了sql和include的使用,其中使用了CDATA段,這是因爲XML標籤本體中出現了於XML標籤衝突的字符,這很好理解。後面兩個查詢就是我們執行的語句部分,程序代碼可以這麼來寫: 
Java代碼  收藏代碼
  1. List users = sqlMap.queryForList("User.getUserAgeOver","23");  
  2. System.out.println(users);  
  3. int userCount = (Integer) sqlMap.queryForObject(  
  4.     "User.getUserCountAgeOver""22");  
  5. System.out.println(userCount);  

    如果可以查詢到記錄,那麼就會打印出來了。上面的例子中我們是用了#來標識傳遞的參數,#被成爲佔位符,這是內聯參數的傳遞方式的一種。 
Xml代碼  收藏代碼
  1. <select id="getUserById" resultClass="User">  
  2.     select  
  3.         userId,  
  4.         userName,  
  5.         password,  
  6.         age,  
  7.         mobile,  
  8.         mail  
  9.     from  
  10.         users  
  11.     where  
  12.         userId = #value#  
  13. </select>  

    在程序中,用下面這些代碼就能達到查詢效果了。 
Java代碼  收藏代碼
  1. User user = (User) sqlMap.queryForObject("User.getUserById"new Integer(1));  
  2. System.out.println(user);  

    #value#是告訴iBatis傳遞一個簡單的參數,iBatis處理該語句時,將會把#value#轉換爲預處理參數形式,然後將這個參數的值設置爲1(就是queryForObject()方法的第二個參數),之後執行該預處理語句。最後iBatis接受返回的結果,然後把它映射到一個Java對象並返回該對象,這就是sqlMap的執行過程。 
    下面來看另外一種內聯參數形式,就是使用$作爲佔位符。它可以直接把參數插入到SQL語句中,這在該SQL語句被轉變爲參數化語句之前就執行了。如此就會留下安全隱患,它可能給SQL注入有機可乘,而且過度使用還會有性能問題,看下面這個語句: 
Xml代碼  收藏代碼
  1. <select id="getUserByLikeEmail" resultClass="User">  
  2.     select  
  3.         userId,  
  4.         userName,  
  5.         password,  
  6.         age,  
  7.         mobile,  
  8.         email  
  9.     from  
  10.         users  
  11.     where  
  12.         email like '%$value$%'  
  13. </select>  

在程序中,我們可以使用如下代碼來執行模糊查詢: 
List<User> users = sqlMap.queryForList("User.getUserByLikeEmail", "gmail"); 
System.out.println(users); 
    若要使用#方式來當佔位符,那麼模糊查詢時可能不是那麼方便,需要如下進行:email like concat('%',#value#,'%'),這是MySQL的情況。所以模糊查詢使用$比較方便。 
    以上的查詢中我們使用了resultClass這種自動結果映射,這是iBatis的一種執行機制,而我們也可以進行自定義結果映射,就是使用resultMap。如果我們在查詢中兩者都沒有使用的話,那麼iBatis執行查詢但是不能返回任何東西。 
    當我們使用bean作爲結果映射時要注意如果結果列存在於數據庫而不存在於bean中,那麼我們不會得到任何數據,而且執行不會報錯。自動映射使用起來很方便,但是更穩健的要數外部結果映射了。 
    如果語句中的字段可變,那麼可以使用動態結果映射,如: 
Xml代碼  收藏代碼
  1. <select id="getUserByLikeEmail" resultClass="User" parameterClass="parameterMap">  
  2.     select  
  3.         userId,  
  4.         userName,  
  5.     <dynamic>  
  6.         <isEqual property="includePassword" compareValue="true">  
  7.             password,  
  8.         </isEqual>  
  9.     </dynamic>  
  10.         age,  
  11.         mobile,  
  12.         email  
  13.     from   
  14.         users   
  15.     where   
  16.         email like concat('%',#email#,'%')  
  17. </select>  

    程序中我們先定義一個ParameterMap類型,然後執行查詢,如下: 
Java代碼  收藏代碼
  1. ParameterMap params = new ParameterMap("email""gmail",  
  2.         "includePassword"true);  
  3. List users = sqlMap.queryForList("User.getUserByLikeEmail", params);  
  4. System.out.println(users);  

    這樣我們就能人爲控制password字段是輸出了。下面我們來看外部參數映射,使用外部參數映射主要是在XML中定義parameterMap,標識它的id和class後再在其中定義parameter,它包括如下屬性:property,javaType,jdbcType,nullValue,mode和typeHandler。要區分這和我們上面定義的ParameterMap類型是兩回事。我們定義的ParameterMap是如下定義的: 
Java代碼  收藏代碼
  1. package ibatis.util;  
  2. import java.util.HashMap;  
  3. public class ParameterMap extends HashMap<Object, Object> {  
  4.     private static final long serialVersionUID = 1L;  
  5.     public ParameterMap(Object... parameters) {  
  6.         for (int i = 0; i < parameters.length - 1; i += 2) {  
  7.             super.put(parameters[i], parameters[i + 1]);  
  8.         }  
  9.     }  
  10. }  

    它是作爲輔助類來用的,給SQL語句提供參數,在配置文件中,我沒使用的是typeAlias來爲它重命名的,而且在select標籤中我們使用的是parameterClass屬性,而不是parameterMap屬性,這裏要區分開,它們可以說是完全不同的。 
    說完了外部參數映射,再說說外部結果映射。上面的例子中我們使用的映射有JavaBean形式的,也有hashmap形式的,但要注意我們是用的都是resultClass屬性來標識它們的,它們都屬於內聯結果映射。外部結果映射是使用resultMap來定義的,我們來看一個實例,來更直觀的說明,首先定義一個resultMap的類型: 
Java代碼  收藏代碼
  1. package ibatis.util;  
  2. public class PrimitiveResult {  
  3.     private int userCount;  
  4.     public int getUserCount() {  
  5.         return userCount;  
  6.     }  
  7.     public void setUserCount(int userCount) {  
  8.         this.userCount = userCount;  
  9.     }  
  10.     @Override  
  11.     public String toString() {  
  12.         return "PrimitiveResult [userCount=" + userCount + "]";  
  13.     }  
  14. }  

    很簡單的一個類型,就是描述用戶數量的。再在XML中定義這個類型: 
Xml代碼  收藏代碼
  1. <resultMap class="ibatis.util.PrimitiveResult" id="primitiveResultMap">  
  2. <result property="userCount" column="userCount" javaType="java.lang.Integer" jdbcType="int" />  
  3. </resultMap>  

    這裏說明一下property就是定義PrimitiveResult中的一個屬性名,這裏是userCount,後面的column應該是數據庫中的字段名,這裏數據庫中沒有統計用戶數量這個字段,我們可以在SQL語句中使用as重命名來進行,javaType和jdbcType就好理解了,分別是Java對象的類型和數據庫字段的類型。 
    下面來看看查詢部分的定義: 
Xml代碼  收藏代碼
  1. <select id="selectPrimitiveByUserId" resultMap="primitiveResultMap">  
  2.     select  
  3.         count(*) as userCount  
  4.     from  
  5.         users  
  6. </select>  

    注意這裏是resultMap就行了,不再是resultClass了,下面就是程序代碼了: 
Java代碼  收藏代碼
  1. PrimitiveResult userCount = (PrimitiveResult) sqlMap.queryForObject(  
  2.             "User.selectPrimitiveByUserId");  
  3. System.out.println(userCount);  

    因爲我們之前在PrimitiveResult中覆蓋了toString()方法,那麼我們執行程序,就得到了:PrimitiveResult [userCount=2],這就是外部結果映射的使用了。 
    最後我們來比較一下javabean的結果映射和map結果映射。Javabean形式的映射都是我們手寫的bean類,而map就直接使用,是內聯情況的。它們各有好處也有缺點。比如使用javabean那麼性能很好,而且是強類型檢測,缺點是很多的get/set方法。而用map不需要很多代碼,但它的效率就慢了,沒有強類型的檢測。 
    一家之言,僅供參考,歡迎交流,希望對使用者有用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章