正如我們所知在mapper文件中用註解的方式寫一些普通的查詢,刪除sql語句格式都相對簡單,而且一般我們如果有動態sql需要的話,可以採用把sql寫在xml文件,然後根據Mapper內方法id進行匹配,實現我們複雜的查詢或者循環添加等操作。
但是如果不寫xml文件而用@Mapper註解方式的話,那如何寫動態SQL?
首先如果註解寫動態sql的話會用到 <script> </scrpit>標籤.
實戰例子1:
1. 多條件查詢以及分頁低配版(返回List集合)
@Select({"<script> SELECT * FROM user WHERE " +
"<if test= "mobile != null and mobile != ''"> mobile = #{mobile} </if>" +
"<if test= "star != null and star != ''"> AND star=#{star} </if>" +
"<if test ='startTime != null '> AND UNIX_TIMESTAMP(update_time) >= #{startTime} </if>" +
"<if test ='endTime != null '> AND UNIX_TIMESTAMP(update_time) <= #{endTime} </if>" +
"<if test="count > 0"> LIMIT #{offset}, #{count} </if> </script>"})
//參數是對象,攜帶多參數進行模糊分頁查詢
List<User> getUserList(Request request);
2. 多條件查詢以及分頁升級版(返回List集合)
//把條件語句單獨提出來,方便其他語句使用,比如查詢數據集合信息,查詢數據條數的sql語句
String QUERY_CODE_SQL = "<if test= \"mobile != null and mobile != ''\"> mobile = #{mobile} </if> " +
"<if test= \"star != null and star != ''\"> AND star=#{star} </if>" +
"<if test ='startTime != null '> AND UNIX_TIMESTAMP(update_time) >= #{startTime} </if>" +
"<if test ='endTime != null '> AND UNIX_TIMESTAMP(update_time) <= #{endTime} </if>" +
"<if test=\"count > 0\"> LIMIT #{offset}, #{count} </if>";
@Select({"<script> SELECT * FROM user WHERE" + QUERY_CODE_SQL + " </script>"})
//參數是對象,攜帶多參數進行模糊分頁查詢集合信息
List<User> getUserList(Request request);
3. 根據某條件循環查詢相關信息(返回List集合)
@Select({"<script> ",
"SELECT * FROM user ",
"WHERE id IN ",
"<foreach collection = 'userIds' separator = ',' open = '(' close = ')' item = 'id'> ",
"#{id} ",
"</foreach> ",
"</script>"})
List<User> getUserListByUserIds(@Param("userIds") Set<Long> userIdSet);
上面例子說明如下:
/**
* 參數爲Set集合,集合內攜帶條件(多個用戶的id==userIds)
* collection :collection屬性的值有三個分別是List、Array、Map三種,分別對應的參數類型爲:List、數組、map集合,我在上面傳的參數爲Set集合(set內沒有重複數據,比List集合實用,避免反覆查詢),所以值爲別名userIds,參數沒有別名的話此處用collection;
* item : 表示在迭代過程中每一個元素的別名
* #{參數} 中的參數名和item別名相對應 #{id} <==> item = 'id'
* open :前綴
* close :後綴
*/
4 根據某條件循環查詢相關信息(返回Map集合)
@Select("<script>" +
"SELECT * FROM user_info WHERE" +
" fellow_id=#{fellow_id} " +
" AND user_id IN " +
"<foreach collection = 'user_ids' separator = ',' open = '(' close = ')' item = 'user_id'>" +
" #{user_id}" +
"</foreach>" +
"</script>")
@MapKey("userId")
Map<String, CalendarTask> getCalendarTaskMap(
@Param("fellow_id") Long fellowId,
@Param("user_ids") List<Long> userIds);
上面例子說明如下:
/**
* 參數1是fellowId;參數2是List集合,集合內攜帶條件(多個用戶的user_id==userIds);
* @MapKey()註解,我理解的是規定Map集合的key,本map的key就是每一個userId,所以參數是該sql語句查詢結果(*查詢出的數據有userId字段)的每條數據中的字段值==>userId;
*/
如果XML元素嵌入在<script>
XML元素中,則可以在註釋值中爲動態SQL使用XML元素:
@Select("<script>SELECT ...</script>")
但是使用<include>
元素會觸發SQL Mapper配置解析異常,由以下原因引起:
org.apache.ibatis.builder.BuilderException: Unknown element in SQL statement. at org.apache.ibatis.scripting.xmltags.XMLScriptBuilder.parseDynamicTags
如果nodeHandlers
在課堂中檢查方法org.apache.ibatis.builder.BuilderException
,將注意到支持的元素有:
- trim
- where
- set
- foreach
- if
- choose
- when
- otherwise
- bind
然而,包括基於註釋的查詢中的片段是不可能的。
5 在@mapper註釋中,動態寫SQL的例子
//bulk insert
@Insert({"<script> ",
"insert into CompletedDeviceData (`gatewayID`,`orderId`,`deviceTypeId`,`dataSampledDate`,`data`,`error`)",
" VALUES ",
" <foreach collection='dataRecordList' separator=',' index= 'index' item='dataRecord'>",
"( #{dataRecord.gatewayID},#{dataRecord.orderId},#{dataRecord.deviceTypeId},",
"#{dataRecord.dataSampledDate},#{dataRecord.data},#{dataRecord.error} )",
"</foreach> ",
"</script>"})
@Options(keyColumn = "recordID", useGeneratedKeys = true)
int batchInsertRecords(@Param("dataRecordList") List<CompletedDeviceDataEntity> dataRecordList);
//bulk update or insert operation
@Insert({"<script> ",
"insert into CompletedDeviceData(`gatewayID`,`orderId`,`deviceTypeId`,`dataSampledDate`,`data`,`error`)",
"VALUES ",
" <foreach collection='dataRecordList' separator = ',' index='index' item='dataRecord'>",
" (#{dataRecord.gatewayID},#{dataRecord.orderId},#{dataRecord.deviceTypeId},",
" #{dataRecord.dataSampledDate},#{dataRecord.data},#{dataRecord.error})",
"</foreach> ",
"ON DUPLICATE KEY UPDATE data=VALUES(data), error=VALUES(error)",
"</script>"})
@Options(keyColumn = "recordID", useGeneratedKeys = true)
int batchUpdateOrInsertRecords(@Param("dataRecordList") List<CompletedDeviceDataEntity> dataRecordList);
注: VALUES 裏面的參數 要用數據庫字段來實現對數據的更新,而不是傳入的參數字段!
參考文檔: