何爲動態SQL??回顧一下咱們以前寫的SSH項目中,有多條件查詢的狀況,以下圖java
咱們當時剛開始作的時候,是須要在Controller中判斷SQL是否已經有條件了,由於SQL語句須要拼接起來….這樣乾的話,就很是容易出錯的。sql
以下的代碼,若是有多個條件的話,那麼拼接起來很容易出錯!數組
public String listUI() { //查詢語句 String hql = "FROM Info i "; List<Object> objectList = new ArrayList<>(); //根據info是否爲null來判斷是不是條件查詢。若是info爲空,那麼是查詢全部。 if (info != null) { if (StringUtils.isNotBlank(info.getTitle())) { hql += "where i.title like ?"; objectList.add("%" + info.getTitle() + "%"); } } infoList = infoServiceImpl.findObjects(hql,objectList); ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP); return "listUI"; }
後來,咱們以爲這樣很差,因而就專門寫了一個查詢助手類:markdown
package zhongfucheng.core.utils; import java.util.ArrayList; import java.util.List; /** * Created by ozc on 2017/6/7. */ public class QueryHelper { private String fromClause = ""; private String whereClause = ""; private String orderbyClause = ""; private List<Object> objectList; public static String ORDER_BY_ASC = "asc"; public static String ORDER_BY_DESC = "desc"; //FROM子句只出現一次 /** * 構建FROM字句,並設置查詢哪張表 * @param aClass 用戶想要操做的類型 * @param alias 別名 */ public QueryHelper(Class aClass, String alias) { fromClause = " FROM " + aClass.getSimpleName() + " " + alias; } //WHERE字句能夠添加多個條件,但WHERE關鍵字只出現一次 /** * 構建WHERE字句 * @param condition * @param objects * @return */ public QueryHelper addCondition(String condition, Object... objects) { //若是已經有字符了,那麼就說明已經有WHERE關鍵字了 if (whereClause.length() > 0) { whereClause += " AND " + condition; } else { whereClause += " WHERE" + condition; } //在添加查詢條件的時候,?對應的查詢條件值 if (objects == null) { objectList = new ArrayList<>(); } for (Object object : objects) { objectList.add(object); } return this; } /** * * @param property 要排序的屬性 * @param order 是升序仍是降序 * @return */ public QueryHelper orderBy(String property, String order) { //若是已經有字符了,那麼就說明已經有ORDER關鍵字了 if (orderbyClause.length() > 0) { orderbyClause += " , " + property +" " + order; } else { orderbyClause += " ORDER BY " + property+" " + order; } return this; } /** * 返回HQL語句 */ public String returnHQL() { return fromClause + whereClause + orderbyClause; } /** * 獲得參數列表 * @return */ public List<Object> getObjectList() { return objectList; } }
這樣一來的話,咱們就不用本身手動拼接了,給咱們的查詢助手類去拼接就行了。ide
而若是咱們使用Mybatis的話,就能夠免去查詢助手類了。由於Mybatis內部就有動態SQL的功能【動態SQL就是自動拼接SQL語句】!測試
<!--多條件查詢【動態SQL】--> <!--會自動組合成一個正常的WHERE字句--> <!--name值會從map中尋找--> <select id="findByCondition" resultMap="studentMap" parameterType="map"> select * from students <where> <if test="name!=null"> and name=#{name} </if> <if test="sal!=null"> and sal < #{sal} </if> </where> </select>
查詢出來小於9000塊的人this
public List<Student> findByCondition(String name,Double sal) throws Exception { //獲得鏈接對象 SqlSession sqlSession = MybatisUtil.getSqlSession(); try{ //映射文件的命名空間.SQL片斷的ID,就能夠調用對應的映射文件中的SQL /** * 因爲咱們的參數超過了兩個,而方法中只有一個Object參數收集 * 所以咱們使用Map集合來裝載咱們的參數 */ Map<String, Object> map = new HashMap(); map.put("name", name); map.put("sal", sal); return sqlSession.selectList("StudentID.findByCondition", map); }catch(Exception e){ e.printStackTrace(); sqlSession.rollback(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } public static void main(String[] args) throws Exception { StudentDao studentDao = new StudentDao(); List<Student> students = studentDao.findByCondition(null,9000D); for (Student student : students) { System.out.println(student.getId() + "---" + student.getName() + "----" + student.getSal()); } }
<!--動態更新--> <!--不要忘了逗號--> <update id="updateByConditions" parameterType="map"> update students <set> <if test="name!=null"> name = #{name}, </if> <if test="sal!=null"> sal = #{sal}, </if> </set> where id = #{id} </update>
給出三個更新的字段spa
public void updateByConditions(int id,String name,Double sal) throws Exception { //獲得鏈接對象 SqlSession sqlSession = MybatisUtil.getSqlSession(); try{ //映射文件的命名空間.SQL片斷的ID,就能夠調用對應的映射文件中的SQL /** * 因爲咱們的參數超過了兩個,而方法中只有一個Object參數收集 * 所以咱們使用Map集合來裝載咱們的參數 */ Map<String, Object> map = new HashMap(); map.put("id", id); map.put("name", name); map.put("sal", sal); sqlSession.update("StudentID.updateByConditions", map); sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); sqlSession.rollback(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } public static void main(String[] args) throws Exception { StudentDao studentDao = new StudentDao(); studentDao.updateByConditions(2,"haha",500D); }
之前咱們使用JDBC也好,Hibernate也好,想要批量刪除的時候,老是使用的是循環刪除。而咱們如今使用的是Mybatis,SQL語句是本身寫的。因此咱們能夠寫下以下的SQL來進行刪除code
delete from students where id in (?,?,?,?);
而咱們的Mybatis又支持動態SQL,因此刪除起來就很是方便了!server
<delete id="deleteByConditions" parameterType="int"> <!-- foreach用於迭代數組元素 open表示開始符號 close表示結束符合 separator表示元素間的分隔符 item表示迭代的數組,屬性值能夠任意,但提倡與方法的數組名相同 #{ids}表示數組中的每一個元素值 --> delete from students where id in <foreach collection="array" open="(" close=")" separator="," item="ids"> #{ids} </foreach> </delete>
刪除編號爲2,3,4的記錄
public void deleteByConditions(int... ids) throws Exception { //獲得鏈接對象 SqlSession sqlSession = MybatisUtil.getSqlSession(); try{ //映射文件的命名空間.SQL片斷的ID,就能夠調用對應的映射文件中的SQL /** * 因爲咱們的參數超過了兩個,而方法中只有一個Object參數收集 * 所以咱們使用Map集合來裝載咱們的參數 */ sqlSession.delete("StudentID.deleteByConditions", ids); sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); sqlSession.rollback(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } public static void main(String[] args) throws Exception { StudentDao studentDao = new StudentDao(); studentDao.deleteByConditions(2,3,4); }
咱們要想動態插入的話,就比其餘的DML語句稍微複雜一點,由於它有兩部分是不肯定的,日常的SQL語句是這樣的:
insert into student(id,name,sal) values(?,?,?)
SQL代碼塊是不能像以前那樣幫咱們自動去除多餘的逗號的,所以咱們須要使用trim標籤來本身手動去除…
編寫insertSQL語句的時候,不要忘了寫()括號。
<!--SQL片斷默認是不幫咱們自動生成合適的SQL,所以須要咱們本身手動除去逗號--> <sql id="key"> <trim suffixOverrides=","> <if test="id!=null"> id, </if> <if test="id!=null"> name, </if> <if test="id!=null"> sal, </if> </trim> </sql> <sql id="value"> <trim suffixOverrides=","> <if test="id!=null"> #{id}, </if> <if test="id!=null"> #{name}, </if> <if test="id!=null"> #{sal}, </if> </trim> </sql> <!--動態插入--> <insert id="insertByConditions" parameterType="zhongfucheng.Student"> insert into students (<include refid="key"/>) values (<include refid="value"/>) </insert>
測試三個不一樣內容的數據
public void insertByConditions(Student student) throws Exception { //獲得鏈接對象 SqlSession sqlSession = MybatisUtil.getSqlSession(); try{ //映射文件的命名空間.SQL片斷的ID,就能夠調用對應的映射文件中的SQL sqlSession.insert("StudentID.insertByConditions", student); sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); sqlSession.rollback(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } public static void main(String[] args) throws Exception { StudentDao studentDao = new StudentDao(); studentDao.insertByConditions(new Student(55, null, null));//name和sal爲空 studentDao.insertByConditions(new Student(66, "haxi", null));//sal爲空 studentDao.insertByConditions(new Student(77, null, 3999d));//name爲空 }