動態SQl是MyBatis的強大特性之一,能夠完成對SQL語句的動態組裝。java
好比說傳入一個User對象,要根據這個User中的數據查詢用戶的完整信息:mysql
有時候sql語句不是一成不變的,要根據傳入的數據動態生成要執行的sql語句,動態sql就適合這種狀況。sql
最好將日誌的控制檯輸出級別設置爲DEBUG,這樣在控臺能看到SQL語句。數據庫
<select id="queryUser" parameterType="user" resultType="user"> SELECT * FROM user_tb <where> <if test="name!=null and name!=''"> name=#{name} </if> <if test="tel!=null and tel!=''"> AND tel=#{tel} </if> </where> </select>
<where>至關於sql語句中的關鍵字WHERE。數組
<if>中的test表示條件,條件成立就把元素體中的字符串拼接到sql語句中,不然不拼接。mybatis
tel不進行數學運算,使用字符串類型。oracle
<where>中有<if>成立時,<where>纔會在sql語句中添加WHERE關鍵字,不然不添加。app
<where>會自動剔除元素體中多餘的AND、OR。ide
好比傳入的User對象只設置了tel,拼接的sql語句是:SELECT * FROM user_tb WHERE AND tel=#{tel},<where>會自動剔除多餘的AND。spa
不使用<where>的寫法:
<select id="queryUser" parameterType="user" resultType="user"> SELECT * FROM user_tb WHERE 1=1 <if test="name!=null and name!=''"> AND name=#{name} </if> <if test="tel!=null and tel!=''"> AND tel=#{tel} </if> </select>
<where>會自動去掉多餘的AND,但不會自動加上缺乏的AND,咱們一般在每一個<if>中都加上AND,防止把AND寫掉了。
<trim>能夠定製須要的功能,好比使用<trim>達到<where>的效果:
<select id="queryUser" parameterType="user" resultType="user"> SELECT * FROM user_tb <trim prefix="WHERE" prefixOverrides="AND"> <if test="name!=null and name!=''"> name=#{name} </if> <if test="tel!=null and tel!=''"> AND tel=#{tel} </if> </trim> </select>
prefix會在這段字符串以前加上指定的前綴,若是裏面的<if>都不知足條件,則不加前綴。
prefixOverrides指定要去除的多餘的字符串。
有時候咱們只須要從多個選項中選擇一個,好比登陸教務系統,讓你選擇角色:數據庫管理員、教職工、學生:
<select id="queryPwd" parameterType="user" resultType="string"> SELECT password FROM user_tb WHERE name=#{name} <choose> <when test="role=='admin'"> AND role='admin' </when> <when test="role=='teacher'"> AND role='teacher' </when> <when test="role=='student'"> AND role='student' </when> </choose> </select>
傳入的值是admin、teacher、student,數據庫中的role字段也是這幾個值,這種傳入的值和數據庫中存儲的值一致的能夠直接這樣寫:
<select id="queryPwd" parameterType="user" resultType="string"> SELECT password FROM user_tb WHERE name=#{name} AND role=#{role} </select>
若是不一致,好比性別,傳入的是male、female,數據庫中存儲的是0、1,就須要使用<choose>轉換一下。
<choose> <when test=""> </when> <when test=""> </when> <otherwise> </otherwise> </choose>
<choose>至關於switch,<when>至關於case,<otherwise>至關於default。
更新操做傳入一個pojo類的對象,但咱們並不知道哪些屬性是有值的(須要更新的),不能更新所有字段,由於有的字段沒有手動賦值,不能用JVM賦的null、0去覆蓋數據表中原來的值。
<set>可解決此問題:
<select id="updateUser" parameterType="user"> UPDATE user_tb <set> <if test="name!=null and name!=''"> name=#{name}, </if> <if test="tel!=null and tel!=''"> tel=#{tel}, </if> <if test="address!=null and address!=''"> name=#{name}, </if> </set> where id=#{id} </select>
<set>用於傳入pojo類型,更新數據表的多個字段。先判斷字段是否有值,有值才更新該字段。
<set>用於更新操做,會自動在這段字符串前面加sql關鍵字「SET」(裏面有<if>爲真),並自動去除多餘的逗號(通常本身寫第一個<if>,而後copy下來改,最後面每每會多一個逗號)。
若是裏面的<if>都爲假,即沒有要更新的字段,不會自動在前面加」SET」,此時這個update語句有語法錯誤,會報錯,因此要保證至少有一個字段須要更新。
<foreach>用於迭代集合、數組,常和in搭配使用。
好比按照手機號隨機抽取3位幸運觀衆(根據手機號碼查詢用戶信息):
<select id="queryUser" parameterType="list" resultType="user"> SELECT * FROM user_tb WHERE tel IN <foreach collection="list" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select>
ArrayList<String> telList = new ArrayList<>(); telList.add("110"); telList.add("119"); telList.add("120"); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.queryUser(telList); System.out.println(userList);
collection是必需的,其他都可選。
更嚴謹的寫法:
<select id="queryUser" parameterType="list" resultType="user"> SELECT * FROM user_tb WHERE tel IN <if test="list!=null and list.size>0"> <foreach collection="list" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </if> </select>
若是傳入的是List類型,要使用List對象自己時,約定使用list表示List對象自己。
模糊查詢時可使用${}鏈接字符串,但不能防止sql注入。
mysql可使用concat()鏈接字符串,oracle可使用||鏈接字符串,但只能針對特定的數據庫使用,不利於項目移植。
mybatis的<bind>元素能夠解決以上問題。
<select id="queryUser" parameterType="string" resultType="user">
<bind name="pattern_name" value="'%'+name+'%'"/>
SELECT * FROM user_tb WHERE name LIKE #{pattern_name}
</select>
<bind>定義一個變量,拼接好字符串。
在sql語句中引用該變量的值。