詳解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(); }