詳解Java的MyBatis框架中靜態SQL的根本用法。本站提示廣大學習愛好者:(詳解Java的MyBatis框架中靜態SQL的根本用法)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解Java的MyBatis框架中靜態SQL的根本用法正文
有些時刻,sql語句where前提中,須要一些平安斷定,例如按某一前提查詢時假如傳入的參數是空,此時查詢出的成果極可能是空的,或許我們須要參數為空時,是查出全體的信息。應用Oracle的序列、mysql的函數生成Id。這時候我們可使用靜態sql。下文均采取mysql語法和函數(例如字符串鏈接函數CONCAT)。
selectKey 標簽
在insert語句中,在Oracle常常應用序列、在MySQL中應用函數來主動生成拔出表的主鍵,並且須要辦法能前往這個生成主鍵。應用myBatis的selectKey標簽可以完成這個後果。上面例子,應用mysql數據庫自界說函數nextval('student'),用來生成一個key,並把他設置到傳入的實體類中的studentId屬性上。所以在履行完此辦法後,邊可以經由過程這個實體類獲得生成的key。
<!-- 拔出先生 主動主鍵-->
<insert id="createStudentAutoKey" parameterType="liming.student.manager.data.model.StudentEntity" keyProperty="studentId">
<selectKey keyProperty="studentId" resultType="String" order="BEFORE">
select nextval('student')
</selectKey>
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})
</insert>
挪用接口辦法,和獲得主動生成key
StudentEntity entity = new StudentEntity();
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());
selectKey語句屬性設置裝備擺設細節:
屬性
描寫
取值
keyProperty
selectKey 語句生成成果須要設置的屬性。
resultType
生成成果類型,MyBatis 許可應用根本的數據類型,包含String 、int類型。
order
1:BEFORE,會先選擇主鍵,然後設置keyProperty,再履行insert語句;
2:AFTER,就先運轉insert 語句再運轉selectKey 語句。BEFORE
AFTER statementType MyBatis 支撐STATEMENT,PREPARED和CALLABLE 的語句情勢, 對應Statement ,PreparedStatement 和CallableStatement 呼應STATEMENT
PREPARED
CALLABLEif標簽
if標簽可用在很多類型的sql語句中,我們以查詢為例。起首看一個很通俗的查詢:
<!-- 查詢先生list,like姓名 -->
<select id="getStudentListLikeName" parameterType="StudentEntity" resultMap="studentResultMap">
SELECT * from STUDENT_TBL ST
WHERE ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%')
</select>
然則此時假如studentName或studentSex為null,此語句極可能報錯或查詢成果為空。此時我們應用if靜態sql語句先輩行斷定,假如值為null或等於空字符串,我們就不停止此前提的斷定,增長靈巧性。
參數為實體類StudentEntity。將實體類中一切的屬性均停止斷定,假如不為空則履行斷定前提。
<!-- 2 if(斷定參數) - 將實體類不為空的屬性作為where前提 -->
<select id="getStudentList_if" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity">
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
<if test="studentName !=null ">
ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')
</if>
<if test="studentSex != null and studentSex != '' ">
AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}
</if>
<if test="studentBirthday != null ">
AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}
</if>
<if test="classId != null and classId!= '' ">
AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}
</if>
<if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">
AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}
</if>
<if test="placeId != null and placeId != '' ">
AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}
</if>
<if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">
AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}
</if>
<if test="studentId != null and studentId != '' ">
AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}
</if>
</select>
應用時比擬靈巧, new一個如許的實體類,我們須要限制誰人前提,只須要附上響應的值就會where這個前提,相反不去賦值便可以不在where中斷定。
public void select_test_2_1() {
StudentEntity entity = new StudentEntity();
entity.setStudentName("");
entity.setStudentSex(1);
entity.setStudentBirthday(DateUtil.parse("1985-05-28"));
entity.setClassId("20000001");
//entity.setPlaceId("70000001");
List<StudentEntity> list = this.dynamicSqlMapper.getStudentList_if(entity);
for (StudentEntity e : list) {
System.out.println(e.toString());
}
}
if + where 的前提斷定
當where中的前提應用的if標簽較多時,如許的組合能夠會招致毛病。我們以在3.1中的查詢語句為例子,當java代碼按以下辦法挪用時:
@Test
public void select_test_2_1() {
StudentEntity entity = new StudentEntity();
entity.setStudentName(null);
entity.setStudentSex(1);
List<StudentEntity> list = this.dynamicSqlMapper.getStudentList_if(entity);
for (StudentEntity e : list) {
System.out.println(e.toString());
}
}
假如下面例子,參數studentName為null,將不會停止STUDENT_NAME列的斷定,則會直接導“WHERE AND”症結字過剩的毛病SQL。
這時候我們可使用where靜態語句來處理。這個“where”標簽會曉得假如它包括的標簽中有前往值的話,它就拔出一個‘where'。另外,假如標簽前往的內容是以AND 或OR 開首的,則它會剔除失落。
下面例子修正為:
<!-- 3 select - where/if(斷定參數) - 將實體類不為空的屬性作為where前提 -->
<select id="getStudentList_whereIf" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity">
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>
<if test="studentName !=null ">
ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')
</if>
<if test="studentSex != null and studentSex != '' ">
AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}
</if>
<if test="studentBirthday != null ">
AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}
</if>
<if test="classId != null and classId!= '' ">
AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}
</if>
<if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">
AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}
</if>
<if test="placeId != null and placeId != '' ">
AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}
</if>
<if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">
AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}
</if>
<if test="studentId != null and studentId != '' ">
AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}
</if>
</where>
</select>
if + set 的更新語句
當update語句中沒有應用if標簽時,假如有一個參數為null,都邑招致毛病。
當在update語句中應用if標簽時,假如後面的if沒有履行,則或招致逗號過剩毛病。應用set標簽可以將靜態的設置裝備擺設SET 症結字,和剔除追加到前提末尾的任何不相干的逗號。
應用if+set標簽修正後,假如某項為null則不停止更新,而是堅持數據庫原值。以下示例:
<!-- 4 if/set(斷定參數) - 將實體類不為空的屬性更新 -->
<update id="updateStudent_if_set" parameterType="liming.student.manager.data.model.StudentEntity">
UPDATE STUDENT_TBL
<set>
<if test="studentName != null and studentName != '' ">
STUDENT_TBL.STUDENT_NAME = #{studentName},
</if>
<if test="studentSex != null and studentSex != '' ">
STUDENT_TBL.STUDENT_SEX = #{studentSex},
</if>
<if test="studentBirthday != null ">
STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday},
</if>
<if test="studentPhoto != null ">
STUDENT_TBL.STUDENT_PHOTO = #{studentPhoto, javaType=byte[], jdbcType=BLOB, typeHandler=org.apache.ibatis.type.BlobTypeHandler},
</if>
<if test="classId != '' ">
STUDENT_TBL.CLASS_ID = #{classId}
</if>
<if test="placeId != '' ">
STUDENT_TBL.PLACE_ID = #{placeId}
</if>
</set>
WHERE STUDENT_TBL.STUDENT_ID = #{studentId};
</update>
if + trim取代where/set標簽
trim是更靈巧的行止過剩症結字的標簽,他可以理論where和set的後果。
trim取代where
<!-- 5.1 if/trim取代where(斷定參數) - 將實體類不為空的屬性作為where前提 -->
<select id="getStudentList_if_trim" resultMap="resultMap_studentEntity">
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
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="studentName !=null ">
ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')
</if>
<if test="studentSex != null and studentSex != '' ">
AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}
</if>
<if test="studentBirthday != null ">
AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}
</if>
<if test="classId != null and classId!= '' ">
AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}
</if>
<if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">
AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}
</if>
<if test="placeId != null and placeId != '' ">
AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}
</if>
<if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">
AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}
</if>
<if test="studentId != null and studentId != '' ">
AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}
</if>
</trim>
</select>
trim取代set
<!-- 5.2 if/trim取代set(斷定參數) - 將實體類不為空的屬性更新 -->
<update id="updateStudent_if_trim" parameterType="liming.student.manager.data.model.StudentEntity">
UPDATE STUDENT_TBL
<trim prefix="SET" suffixOverrides=",">
<if test="studentName != null and studentName != '' ">
STUDENT_TBL.STUDENT_NAME = #{studentName},
</if>
<if test="studentSex != null and studentSex != '' ">
STUDENT_TBL.STUDENT_SEX = #{studentSex},
</if>
<if test="studentBirthday != null ">
STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday},
</if>
<if test="studentPhoto != null ">
STUDENT_TBL.STUDENT_PHOTO = #{studentPhoto, javaType=byte[], jdbcType=BLOB, typeHandler=org.apache.ibatis.type.BlobTypeHandler},
</if>
<if test="classId != '' ">
STUDENT_TBL.CLASS_ID = #{classId},
</if>
<if test="placeId != '' ">
STUDENT_TBL.PLACE_ID = #{placeId}
</if>
</trim>
WHERE STUDENT_TBL.STUDENT_ID = #{studentId}
</update>
choose (when, otherwise)
有時刻我們其實不想運用一切的前提,而只是想從多個選項當選擇一個。而應用if標簽時,只需test中的表達式為true,就會履行if標簽中的前提。MyBatis供給了choose 元素。if標簽是與(and)的關系,而choose比傲天是或(or)的關系。
choose標簽是按次序斷定其外部when標簽中的test前提出否成立,假如有一個成立,則choose停止。當choose中一切when的前提都不滿則時,則履行otherwise中的sql。相似於Java 的switch 語句,choose為switch,when為case,otherwise則為default。
例以下面例子,異樣把一切可以限制的前提都寫上,方面應用。choose會從上到下選擇一個when標簽的test為true的sql履行。平安斟酌,我們應用where將choose包起來,放置症結字多於毛病。
<!-- 6 choose(斷定參數) - 按次序將實體類第一個不為空的屬性作為where前提 -->
<select id="getStudentList_choose" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity">
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>
<choose>
<when test="studentName !=null ">
ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')
</when >
<when test="studentSex != null and studentSex != '' ">
AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}
</when >
<when test="studentBirthday != null ">
AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}
</when >
<when test="classId != null and classId!= '' ">
AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}
</when >
<when test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">
AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}
</when >
<when test="placeId != null and placeId != '' ">
AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}
</when >
<when test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">
AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}
</when >
<when test="studentId != null and studentId != '' ">
AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}
</when >
<otherwise>
</otherwise>
</choose>
</where>
</select>
foreach
關於靜態SQL 異常必需的,主是要迭代一個聚集,平日是用於IN 前提。List 實例將應用“list”做為鍵,數組實例以“array” 做為鍵。
foreach元素長短常壯大的,它許可你指定一個聚集,聲明聚集項和索引變量,它們可以用在元素體內。它也許可你指定開放和封閉的字符串,在迭代之間放置分隔符。這個元素是很智能的,它不會有時地附加過剩的分隔符。
留意:你可以傳遞一個List實例或許數組作為參數對象傳給MyBatis。當你這麼做的時刻,MyBatis會主動將它包裝在一個Map中,用稱號在作為鍵。List實例將會以“list”作為鍵,而數組實例將會以“array”作為鍵。
這個部門是對關於XML設置裝備擺設文件和XML映照文件的而評論辯論的。下一部門將具體評論辯論Java API,所以你可以獲得你曾經創立的最有用的映照。
1.參數為array示例的寫法
接口的辦法聲明:
public List<StudentEntity> getStudentListByClassIds_foreach_array(String[] classIds);
靜態SQL語句:
<!— 7.1 foreach(輪回array參數) - 作為where中in的前提 -->
<select id="getStudentListByClassIds_foreach_array" resultMap="resultMap_studentEntity">
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
<foreach collection="array" item="classIds" open="(" separator="," close=")">
#{classIds}
</foreach>
</select>
測試代碼,查詢先生中,在20000001、20000002這兩個班級的先生:
@Test
public void test7_foreach() {
String[] classIds = { "20000001", "20000002" };
List<StudentEntity> list = this.dynamicSqlMapper.getStudentListByClassIds_foreach_array(classIds);
for (StudentEntity e : list) {
System.out.println(e.toString());
}
}
2.參數為list示例的寫法
接口的辦法聲明:
public List<StudentEntity> getStudentListByClassIds_foreach_list(List<String> classIdList);
靜態SQL語句:
<!-- 7.2 foreach(輪回List<String>參數) - 作為where中in的前提 -->
<select id="getStudentListByClassIds_foreach_list" resultMap="resultMap_studentEntity">
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
<foreach collection="list" item="classIdList" open="(" separator="," close=")">
#{classIdList}
</foreach>
</select>
測試代碼,查詢先生中,在20000001、20000002這兩個班級的先生:
@Test
public void test7_2_foreach() {
ArrayList<String> classIdList = new ArrayList<String>();
classIdList.add("20000001");
classIdList.add("20000002");
List<StudentEntity> list = this.dynamicSqlMapper.getStudentListByClassIds_foreach_list(classIdList);
for (StudentEntity e : list) {
System.out.println(e.toString());
}
}
3.本身把參數封裝成Map的類型
<select id="dynamicForeach3Test" resultType="Blog">
select * from t_blog where title like "%"#{title}"%" and id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
上述collection的值為ids,是傳入的參數Map的key,對應的Mapper代碼:
public List<Blog> dynamicForeach3Test(Map<String, Object> params);
對應測試代碼:
@Test
public void dynamicForeach3Test() {
SqlSession session = Util.getSqlSessionFactory().openSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
final List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(6);
ids.add(7);
ids.add(9);
Map<String, Object> params = new HashMap<String, Object>();
params.put("ids", ids);
params.put("title", "中國");
List<Blog> blogs = blogMapper.dynamicForeach3Test(params);
for (Blog blog : blogs)
System.out.println(blog);
session.close();
}