iBatis開發詳解(4)-----------select詳解
阿新 • • 發佈:2019-02-15
<select>是iBatis已經對映的語句型別,就是查詢了,為了配合說明,這裡再介紹兩個標記:<sql>和<include>,前者用來建立一個文字片段,這些片段可以組合起來建立完整的SQL語句;後者很顯然就是包含的意思了。假設我們有如下程式碼段:
Xml程式碼
該部分程式碼展示了sql和include的使用,其中使用了CDATA段,這是因為XML標籤本體中出現了於XML標籤衝突的字元,這很好理解。後面兩個查詢就是我們執行的語句部分,程式程式碼可以這麼來寫:
Java程式碼
如果可以查詢到記錄,那麼就會打印出來了。上面的例子中我們是用了#來標識傳遞的引數,#被成為佔位符,這是內聯引數的傳遞方式的一種。
Xml程式碼
在程式中,用下面這些程式碼就能達到查詢效果了。
Java程式碼
#value#是告訴iBatis傳遞一個簡單的引數,iBatis處理該語句時,將會把#value#轉換為預處理引數形式,然後將這個引數的值設定為1(就是queryForObject()方法的第二個引數),之後執行該預處理語句。最後iBatis接受返回的結果,然後把它對映到一個Java物件並返回該物件,這就是sqlMap的執行過程。
下面來看另外一種內聯引數形式,就是使用$作為佔位符。它可以直接把引數插入到SQL語句中,這在該SQL語句被轉變為引數化語句之前就執行了。如此就會留下安全隱患,它可能給SQL注入有機可乘,而且過度使用還會有效能問題,看下面這個語句:
Xml程式碼
在程式中,我們可以使用如下程式碼來執行模糊查詢:
List<User> users = sqlMap.queryForList("User.getUserByLikeEmail", "gmail");
System.out.println(users);
若要使用#方式來當佔位符,那麼模糊查詢時可能不是那麼方便,需要如下進行:email like concat('%',#value#,'%'),這是MySQL的情況。所以模糊查詢使用$比較方便。
以上的查詢中我們使用了resultClass這種自動結果對映,這是iBatis的一種執行機制,而我們也可以進行自定義結果對映,就是使用resultMap。如果我們在查詢中兩者都沒有使用的話,那麼iBatis執行查詢但是不能返回任何東西。
當我們使用bean作為結果對映時要注意如果結果列存在於資料庫而不存在於bean中,那麼我們不會得到任何資料,而且執行不會報錯。自動對映使用起來很方便,但是更穩健的要數外部結果映射了。
如果語句中的欄位可變,那麼可以使用動態結果對映,如:
Xml程式碼
程式中我們先定義一個ParameterMap型別,然後執行查詢,如下:
Java程式碼
這樣我們就能人為控制password欄位是輸出了。下面我們來看外部引數對映,使用外部引數對映主要是在XML中定義parameterMap,標識它的id和class後再在其中定義parameter,它包括如下屬性:property,javaType,jdbcType,nullValue,mode和typeHandler。要區分這和我們上面定義的ParameterMap型別是兩回事。我們定義的ParameterMap是如下定義的:
Java程式碼
它是作為輔助類來用的,給SQL語句提供引數,在配置檔案中,我沒使用的是typeAlias來為它重新命名的,而且在select標籤中我們使用的是parameterClass屬性,而不是parameterMap屬性,這裡要區分開,它們可以說是完全不同的。
說完了外部引數對映,再說說外部結果對映。上面的例子中我們使用的對映有JavaBean形式的,也有hashmap形式的,但要注意我們是用的都是resultClass屬性來標識它們的,它們都屬於內聯結果對映。外部結果對映是使用resultMap來定義的,我們來看一個例項,來更直觀的說明,首先定義一個resultMap的型別:
Java程式碼
很簡單的一個型別,就是描述使用者數量的。再在XML中定義這個型別:
Xml程式碼
這裡說明一下property就是定義PrimitiveResult中的一個屬性名,這裡是userCount,後面的column應該是資料庫中的欄位名,這裡資料庫中沒有統計使用者數量這個欄位,我們可以在SQL語句中使用as重新命名來進行,javaType和jdbcType就好理解了,分別是Java物件的型別和資料庫欄位的型別。
下面來看看查詢部分的定義:
Xml程式碼
注意這裡是resultMap就行了,不再是resultClass了,下面就是程式程式碼了:
Java程式碼
因為我們之前在PrimitiveResult中覆蓋了toString()方法,那麼我們執行程式,就得到了:PrimitiveResult [userCount=2],這就是外部結果對映的使用了。
最後我們來比較一下javabean的結果對映和map結果對映。Javabean形式的對映都是我們手寫的bean類,而map就直接使用,是內聯情況的。它們各有好處也有缺點。比如使用javabean那麼效能很好,而且是強型別檢測,缺點是很多的get/set方法。而用map不需要很多程式碼,但它的效率就慢了,沒有強型別的檢測。
Xml程式碼
- <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標籤本體中出現了於XML標籤衝突的字元,這很好理解。後面兩個查詢就是我們執行的語句部分,程式程式碼可以這麼來寫:
Java程式碼
-
List users = sqlMap.queryForList("User.getUserAgeOver"
- System.out.println(users);
- int userCount = (Integer) sqlMap.queryForObject(
- "User.getUserCountAgeOver", "22");
- System.out.println(userCount);
如果可以查詢到記錄,那麼就會打印出來了。上面的例子中我們是用了#來標識傳遞的引數,#被成為佔位符,這是內聯引數的傳遞方式的一種。
Xml程式碼
- <select id="getUserById" resultClass="User">
- select
- userId,
- userName,
- password,
- age,
- mobile,
- from
- users
- where
- userId = #value#
- </select>
在程式中,用下面這些程式碼就能達到查詢效果了。
Java程式碼
- User user = (User) sqlMap.queryForObject("User.getUserById", new Integer(1));
- System.out.println(user);
#value#是告訴iBatis傳遞一個簡單的引數,iBatis處理該語句時,將會把#value#轉換為預處理引數形式,然後將這個引數的值設定為1(就是queryForObject()方法的第二個引數),之後執行該預處理語句。最後iBatis接受返回的結果,然後把它對映到一個Java物件並返回該物件,這就是sqlMap的執行過程。
下面來看另外一種內聯引數形式,就是使用$作為佔位符。它可以直接把引數插入到SQL語句中,這在該SQL語句被轉變為引數化語句之前就執行了。如此就會留下安全隱患,它可能給SQL注入有機可乘,而且過度使用還會有效能問題,看下面這個語句:
Xml程式碼
- <select id="getUserByLikeEmail" resultClass="User">
- select
- userId,
- userName,
- password,
- age,
- mobile,
- from
- users
- where
- email like '%$value$%'
- </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程式碼
- <select id="getUserByLikeEmail" resultClass="User" parameterClass="parameterMap">
- select
- userId,
- userName,
- <dynamic>
- <isEqual property="includePassword" compareValue="true">
- password,
- </isEqual>
- </dynamic>
- age,
- mobile,
- from
- users
- where
- email like concat('%',#email#,'%')
- </select>
程式中我們先定義一個ParameterMap型別,然後執行查詢,如下:
Java程式碼
- ParameterMap params = new ParameterMap("email", "gmail",
- "includePassword", true);
- List users = sqlMap.queryForList("User.getUserByLikeEmail", params);
- System.out.println(users);
這樣我們就能人為控制password欄位是輸出了。下面我們來看外部引數對映,使用外部引數對映主要是在XML中定義parameterMap,標識它的id和class後再在其中定義parameter,它包括如下屬性:property,javaType,jdbcType,nullValue,mode和typeHandler。要區分這和我們上面定義的ParameterMap型別是兩回事。我們定義的ParameterMap是如下定義的:
Java程式碼
- 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語句提供引數,在配置檔案中,我沒使用的是typeAlias來為它重新命名的,而且在select標籤中我們使用的是parameterClass屬性,而不是parameterMap屬性,這裡要區分開,它們可以說是完全不同的。
說完了外部引數對映,再說說外部結果對映。上面的例子中我們使用的對映有JavaBean形式的,也有hashmap形式的,但要注意我們是用的都是resultClass屬性來標識它們的,它們都屬於內聯結果對映。外部結果對映是使用resultMap來定義的,我們來看一個例項,來更直觀的說明,首先定義一個resultMap的型別:
Java程式碼
- 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 + "]";
- }
- }
很簡單的一個型別,就是描述使用者數量的。再在XML中定義這個型別:
Xml程式碼
- <resultMap class="ibatis.util.PrimitiveResult" id="primitiveResultMap">
- <result property="userCount" column="userCount" javaType="java.lang.Integer" jdbcType="int" />
- </resultMap>
這裡說明一下property就是定義PrimitiveResult中的一個屬性名,這裡是userCount,後面的column應該是資料庫中的欄位名,這裡資料庫中沒有統計使用者數量這個欄位,我們可以在SQL語句中使用as重新命名來進行,javaType和jdbcType就好理解了,分別是Java物件的型別和資料庫欄位的型別。
下面來看看查詢部分的定義:
Xml程式碼
- <select id="selectPrimitiveByUserId" resultMap="primitiveResultMap">
- select
- count(*) as userCount
- from
- users
- </select>
注意這裡是resultMap就行了,不再是resultClass了,下面就是程式程式碼了:
Java程式碼
- PrimitiveResult userCount = (PrimitiveResult) sqlMap.queryForObject(
- "User.selectPrimitiveByUserId");
- System.out.println(userCount);
因為我們之前在PrimitiveResult中覆蓋了toString()方法,那麼我們執行程式,就得到了:PrimitiveResult [userCount=2],這就是外部結果對映的使用了。
最後我們來比較一下javabean的結果對映和map結果對映。Javabean形式的對映都是我們手寫的bean類,而map就直接使用,是內聯情況的。它們各有好處也有缺點。比如使用javabean那麼效能很好,而且是強型別檢測,缺點是很多的get/set方法。而用map不需要很多程式碼,但它的效率就慢了,沒有強型別的檢測。