用來循環(huán)容器的標簽forEach,查看例子
foreach元素的屬性主要有item,index钦听,collection洒试,open,separator朴上,close垒棋。
item:集合中元素迭代時的別名,
index:集合中元素迭代時的索引
open:常用語where語句中痪宰,表示以什么開始叼架,比如以'('開始
separator:表示在每次進行迭代時的分隔符,
close 常用語where語句中衣撬,表示以什么結束乖订,
在使用foreach的時候最關鍵的也是最容易出錯的就是collection屬性,該屬性是必須指定的具练,但是在不同情況下乍构,該屬性的值是不一樣的,主要有一下3種情況:
如果傳入的是單參數(shù)且參數(shù)類型是一個List的時候扛点,collection屬性值為list .
如果傳入的是單參數(shù)且參數(shù)類型是一個array數(shù)組的時候哥遮,collection的屬性值為array .
如果傳入的參數(shù)是多個的時候,我們就需要把它們封裝成一個Map了陵究,當然單參數(shù)也可以封裝成map眠饮,實際上如果你在傳入?yún)?shù)的時候,在MyBatis里面也是會把它封裝成一個Map的铜邮,map的key就是參數(shù)名仪召,所以這個時候collection屬性值就是傳入的List或array對象在自己封裝的map里面的key.
針對最后一條,我們來看一下官方說法:
注意 你可以將一個 List 實例或者數(shù)組作為參數(shù)對象傳給 MyBatis松蒜,當你這么做的時候返咱,MyBatis 會自動將它包裝在一個 Map 中并以名稱為鍵。List 實例將會以“l(fā)ist”作為鍵牍鞠,而數(shù)組實例的鍵將是“array”咖摹。
所以,不管是多參數(shù)還是單參數(shù)的list,array類型难述,都可以封裝為map進行傳遞萤晴。如果傳遞的是一個List,則mybatis會封裝為一個list為key胁后,list值為object的map店读,如果是array,則封裝成一個array為key攀芯,array的值為object的map屯断,如果自己封裝呢,則colloection里放的是自己封裝的map里的key值
//mapper中我們要為這個方法傳遞的是一個容器,將容器中的元素一個一個的
//拼接到xml的方法中就要使用這個forEach這個標簽了
publicListqueryById(List<String>?userids);
//對應的xml中如下
select*?FROM?entity
whereidin
#{userid}
concat模糊查詢
//比如說我們想要進行條件查詢,但是幾個條件不是每次都要使用,那么我們就可以
//通過判斷是否拼接到sql中
SELECT?*fromentity
name?likeconcat('%',concat(#{name},'%'))
choose (when, otherwise)標簽
choose標簽是按順序判斷其內(nèi)部when標簽中的test條件出否成立,如果有一個成立殖演,則 choose 結束氧秘。當 choose 中所有 when 的條件都不滿則時,則執(zhí)行 otherwise 中的sql趴久。類似于Java 的 switch 語句丸相,choose 為 switch,when 為 case彼棍,otherwise 則為 default灭忠。
例如下面例子,同樣把所有可以限制的條件都寫上座硕,方面使用弛作。choose會從上到下選擇一個when標簽的test為true的sql執(zhí)行。安全考慮华匾,我們使用where將choose包起來映琳,放置關鍵字多于錯誤。
<!--??choose(判斷參數(shù))?-?按順序?qū)嶓w類?User?第一個不為空的屬性作為:where條件?-->
SELECT?*
FROM?User?u
u.username?LIKE?CONCAT(CONCAT('%',?#{username,?jdbcType=VARCHAR}),'%')
AND?u.sex?=?#{sex,?jdbcType=INTEGER}
AND?u.birthday?=?#{birthday,?jdbcType=DATE}
selectKey 標簽
在insert語句中瘦真,在Oracle經(jīng)常使用序列刊头、在MySQL中使用函數(shù)來自動生成插入表的主鍵,而且需要方法能返回這個生成主鍵诸尽。使用myBatis的selectKey標簽可以實現(xiàn)這個效果原杂。?
下面例子,使用mysql數(shù)據(jù)庫自定義函數(shù)nextval('student')您机,用來生成一個key穿肄,并把他設置到傳入的實體類中的studentId屬性上。所以在執(zhí)行完此方法后际看,邊可以通過這個實體類獲取生成的key咸产。
<!--?插入學生?自動主鍵-->
select?nextval('student')
INSERT?INTO?STUDENT_TBL(STUDENT_ID,
STUDENT_NAME,
STUDENT_SEX,
STUDENT_BIRTHDAY,
STUDENT_PHOTO,
CLASS_ID,
PLACE_ID)
VALUES?(#{studentId},
#{studentName},
#{studentSex},
#{studentBirthday},
#{studentPhoto,?javaType=byte[],?jdbcType=BLOB,?typeHandler=org.apache.ibatis.type.BlobTypeHandler},
#{classId},
#{placeId})
調(diào)用接口方法,和獲取自動生成key
StudentEntity?entity?=newStudentEntity();
entity.setStudentName("黎明你好");
entity.setStudentSex(1);
entity.setStudentBirthday(DateUtil.parse("1985-05-28"));
entity.setClassId("20000001");
entity.setPlaceId("70000001");
this.dynamicSqlMapper.createStudentAutoKey(entity);
System.out.println("新增學生ID:?"+?entity.getStudentId());
if標簽
if標簽可用在許多類型的sql語句中仲闽,我們以查詢?yōu)槔砸纭J紫瓤匆粋€很普通的查詢:
<!--?查詢學生list,like姓名?-->
SELECT?*?from?STUDENT_TBL?ST
WHERE?ST.STUDENT_NAME?LIKE?CONCAT(CONCAT('%',?#{studentName}),'%')
但是此時如果studentName為null赖欣,此語句很可能報錯或查詢結果為空屑彻。此時我們使用if動態(tài)sql語句先進行判斷,如果值為null或等于空字符串顶吮,我們就不進行此條件的判斷社牲,增加靈活性。
參數(shù)為實體類StudentEntity悴了。將實體類中所有的屬性均進行判斷搏恤,如果不為空則執(zhí)行判斷條件违寿。
SELECTST.STUDENT_ID,
ST.STUDENT_NAME,
ST.STUDENT_SEX,
ST.STUDENT_BIRTHDAY,
ST.STUDENT_PHOTO,
ST.CLASS_ID,
ST.PLACE_ID
FROMSTUDENT_TBL?ST
WHERE
ST.STUDENT_NAMELIKECONCAT(CONCAT('%',?#{studentName,?jdbcType=VARCHAR}),'%')??
ANDST.STUDENT_SEX?=#{studentSex,?jdbcType=INTEGER}??
ANDST.STUDENT_BIRTHDAY?=#{studentBirthday,?jdbcType=DATE}??
ANDST.CLASS_ID?=#{classId,?jdbcType=VARCHAR}??
ANDST.CLASS_ID?=#{classEntity.classId,?jdbcType=VARCHAR}??
ANDST.PLACE_ID?=#{placeId,?jdbcType=VARCHAR}??
ANDST.PLACE_ID?=#{placeEntity.placeId,?jdbcType=VARCHAR}??
ANDST.STUDENT_ID?=#{studentId,?jdbcType=VARCHAR}??
使用時比較靈活, new一個這樣的實體類熟空,我們需要限制那個條件藤巢,只需要附上相應的值就會where這個條件,相反不去賦值就可以不在where中判斷痛阻。
publicvoidselect_test_2_1(){
StudentEntity?entity?=newStudentEntity();
entity.setStudentName("");
entity.setStudentSex(1);
entity.setStudentBirthday(DateUtil.parse("1985-05-28"));
entity.setClassId("20000001");
//entity.setPlaceId("70000001");??
Listlist=this.dynamicSqlMapper.getStudentList_if(entity);
for(StudentEntity?e?:list)?{
System.out.println(e.toString());
}
}
if + where 的條件判斷
當where中的條件使用的if標簽較多時菌瘪,這樣的組合可能會導致錯誤腮敌。我們以在3.1中的查詢語句為例子阱当,當java代碼按如下方法調(diào)用時:
@Test
publicvoidselect_test_2_1()
{
StudentEntity?entity?=newStudentEntity();
entity.setStudentName(null);
entity.setStudentSex(1);
Listlist=this.dynamicSqlMapper.getStudentList_if(entity);
for(StudentEntity?e?:list)?{
System.out.println(e.toString());
}
}
如果上面例子,參數(shù)studentName為null糜工,將不會進行STUDENT_NAME列的判斷弊添,則會直接導“WHERE AND”關鍵字多余的錯誤SQL。?
這時我們可以使用where動態(tài)語句來解決捌木。這個“where”標簽會知道如果它包含的標簽中有返回值的話油坝,它就插入一個‘where’。此外刨裆,如果標簽返回的內(nèi)容是以AND 或OR 開頭的澈圈,則它會剔除掉。?
上面例子修改為:
SELECTST.STUDENT_ID,
ST.STUDENT_NAME,
ST.STUDENT_SEX,
ST.STUDENT_BIRTHDAY,
ST.STUDENT_PHOTO,
ST.CLASS_ID,
ST.PLACE_ID
FROMSTUDENT_TBL?ST
ST.STUDENT_NAMELIKECONCAT(CONCAT('%',?#{studentName,?jdbcType=VARCHAR}),'%')??
ANDST.STUDENT_SEX?=#{studentSex,?jdbcType=INTEGER}??
ANDST.STUDENT_BIRTHDAY?=#{studentBirthday,?jdbcType=DATE}??
ANDST.CLASS_ID?=#{classId,?jdbcType=VARCHAR}??
ANDST.CLASS_ID?=#{classEntity.classId,?jdbcType=VARCHAR}??
ANDST.PLACE_ID?=#{placeId,?jdbcType=VARCHAR}??
ANDST.PLACE_ID?=#{placeEntity.placeId,?jdbcType=VARCHAR}??
ANDST.STUDENT_ID?=#{studentId,?jdbcType=VARCHAR}??
if + set實現(xiàn)修改語句
當update語句中沒有使用if標簽時帆啃,如果有一個參數(shù)為null瞬女,都會導致錯誤。?
當在update語句中使用if標簽時努潘,如果前面的if沒有執(zhí)行诽偷,則或?qū)е露禾柖嘤噱e誤。使用set標簽可以將動態(tài)的配置SET 關鍵字疯坤,和剔除追加到條件末尾的任何不相關的逗號报慕。使用if+set標簽修改后,如果某項為null則不進行更新压怠,而是保持數(shù)據(jù)庫原值眠冈。如下示例:
UPDATE?STUDENT_TBL
STUDENT_TBL.STUDENT_NAME?=#{studentName},??
STUDENT_TBL.STUDENT_SEX?=#{studentSex},??
STUDENT_TBL.STUDENT_BIRTHDAY?=#{studentBirthday},??
STUDENT_TBL.STUDENT_PHOTO?=#{studentPhoto,?javaType=byte[],?jdbcType=BLOB,?typeHandler=org.apache.ibatis.type.BlobTypeHandler},??
STUDENT_TBL.CLASS_ID?=#{classId}??
STUDENT_TBL.PLACE_ID?=#{placeId}??
WHERE?STUDENT_TBL.STUDENT_ID?=#{studentId};??????
if + trim代替where/set標簽
trim是更靈活的去處多余關鍵字的標簽,他可以實踐where和set的效果菌瘫。
trim代替where
SELECTST.STUDENT_ID,
ST.STUDENT_NAME,
ST.STUDENT_SEX,
ST.STUDENT_BIRTHDAY,
ST.STUDENT_PHOTO,
ST.CLASS_ID,
ST.PLACE_ID
FROMSTUDENT_TBL?ST
ST.STUDENT_NAMELIKECONCAT(CONCAT('%',?#{studentName,?jdbcType=VARCHAR}),'%')??
ANDST.STUDENT_SEX?=#{studentSex,?jdbcType=INTEGER}??
ANDST.STUDENT_BIRTHDAY?=#{studentBirthday,?jdbcType=DATE}??
ANDST.CLASS_ID?=#{classId,?jdbcType=VARCHAR}??
ANDST.CLASS_ID?=#{classEntity.classId,?jdbcType=VARCHAR}??
ANDST.PLACE_ID?=#{placeId,?jdbcType=VARCHAR}??
ANDST.PLACE_ID?=#{placeEntity.placeId,?jdbcType=VARCHAR}??
ANDST.STUDENT_ID?=#{studentId,?jdbcType=VARCHAR}??
trim代替set
UPDATE?STUDENT_TBL
STUDENT_TBL.STUDENT_NAME?=#{studentName},??
STUDENT_TBL.STUDENT_SEX?=#{studentSex},??
STUDENT_TBL.STUDENT_BIRTHDAY?=#{studentBirthday},??
STUDENT_TBL.STUDENT_PHOTO?=#{studentPhoto,?javaType=byte[],?jdbcType=BLOB,?typeHandler=org.apache.ibatis.type.BlobTypeHandler},??
STUDENT_TBL.CLASS_ID?=#{classId},??
STUDENT_TBL.PLACE_ID?=#{placeId}??
WHERE?STUDENT_TBL.STUDENT_ID?=#{studentId}??
foreach
對于動態(tài)SQL 非常必須的蜗顽,主是要迭代一個集合,通常是用于IN 條件突梦。List 實例將使用“l(fā)ist”做為鍵诫舅,數(shù)組實例以“array” 做為鍵。
foreach元素是非常強大的宫患,它允許你指定一個集合刊懈,聲明集合項和索引變量,它們可以用在元素體內(nèi)。它也允許你指定開放和關閉的字符串虚汛,在迭代之間放置分隔符匾浪。這個元素是很智能的,它不會偶然地附加多余的分隔符卷哩。
注意:你可以傳遞一個List實例或者數(shù)組作為參數(shù)對象傳給MyBatis蛋辈。當你這么做的時候,MyBatis會自動將它包裝在一個Map中将谊,用名稱在作為鍵冷溶。List實例將會以“l(fā)ist”作為鍵,而數(shù)組實例將會以“array”作為鍵尊浓。
這個部分是對關于XML配置文件和XML映射文件的而討論的逞频。下一部分將詳細討論Java API,所以你可以得到你已經(jīng)創(chuàng)建的最有效的映射栋齿。
參數(shù)為array示例的寫法
接口的方法聲明:
publicListgetStudentListByClassIds_foreach_array(String[]?classIds);
動態(tài)SQL語句:
SELECT?ST.STUDENT_ID,
ST.STUDENT_NAME,
ST.STUDENT_SEX,
ST.STUDENT_BIRTHDAY,
ST.STUDENT_PHOTO,
ST.CLASS_ID,
ST.PLACE_ID
FROM?STUDENT_TBL?ST
WHERE?ST.CLASS_ID?IN
#{classIds}
測試代碼苗胀,查詢學生中,在20000001瓦堵、20000002這兩個班級的學生:
@Test
publicvoidtest7_foreach()
{
String[]?classIds?=?{"20000001","20000002"};
Listlist=this.dynamicSqlMapper.getStudentListByClassIds_foreach_array(classIds);
for(StudentEntity?e?:list)?{
System.out.println(e.toString());
}
}
2參數(shù)為list示例的寫法?
接口的方法聲明:
publicList?getStudentListByClassIds_foreach_list(List?classIdList);
動態(tài)SQL語句:
<!--?7.2?foreach(循環(huán)List<String>參數(shù))?-?作為where中in的條件?-->
SELECT?ST.STUDENT_ID,
ST.STUDENT_NAME,
ST.STUDENT_SEX,
ST.STUDENT_BIRTHDAY,
ST.STUDENT_PHOTO,
ST.CLASS_ID,
ST.PLACE_ID
FROM?STUDENT_TBL?ST
WHERE?ST.CLASS_ID?IN
#{classIdList}
測試代碼基协,查詢學生中,在20000001菇用、20000002這兩個班級的學生:
@Test
publicvoidtest7_2_foreach()
{
ArrayList?classIdList?=newArrayList();
classIdList.add("20000001");
classIdList.add("20000002");
List?list?=this.dynamicSqlMapper.getStudentListByClassIds_foreach_list(classIdList);
for(StudentEntity?e?:?list)?{
System.out.println(e.toString());
}
sql片段標簽:通過該標簽可定義能復用的sql語句片段澜驮,在執(zhí)行sql語句標簽中直接引用即可。這樣既可以提高編碼效率刨疼,還能有效簡化代碼泉唁,提高可讀性
需要配置的屬性:id="" >>>表示需要改sql語句片段的唯一標識
引用:通過標簽引用,refid="" 中的值指向需要引用的中的id=“”屬性
<!--定義sql片段-->
o.order_id,o.cid,o.address,o.create_date,o.orderitem_id,i.orderitem_id,i.product_id,i.count
select
<!--引用sql片段-->
from?ordertable?o
join?orderitem?i?on?o.orderitem_id?=?i.orderitem_id
where?o.order_id?=?#{orderId}
?