(3).Mybatis動態sql的使用

Mybatis可以幫助我們方便的在SQL語句中實現某些邏輯。Mybatis動態sql語法常用的標籤有:

  1. 使用_parameter
  2. if判斷
  3. switch判斷(使用choose…when…otherwise語法標籤 )
  4. where子句
  5. set子句
  6. trim語法
  7. foreach迭代變量

_parameter的使用

_parameter 表示當前傳入的參數,如果查詢的時候傳入的參數只有一個,則使用 _parameter
數據庫mybatis1中的表users中現在有記錄如下:

User [id=1, name=aa, phone=13411111111, email=aa@163.com]
User [id=2, name=bb, phone=13422222222, email=bb@163.com]
User [id=3, name=cc, phone=13433333333, email=cc@126.com]
User [id=4, name=dd, phone=13444444444, email=dd@126.com]

現要查詢id值爲4的user信息,返回的結果集爲User對象,userMapper.xml文件中寫法如下:

<select id="getUser1" parameterType="int" resultType="User">
    select id, name, phone, email from users where id = #{_parameter}
</select>

測試代碼:

@Test
public void getUser1(){
    SqlSession session = MybatisUtils.getSession(false);
    User user = session.selectOne("com.qcc.mapping.userMapper.getUser1", 4);
    System.out.println(user);
}

運行結果:User [id=4, name=dd, phone=13444444444, [email protected]]


if判斷

if其實就是簡單的條件判斷,條件成立,就拼接sql語句,不成立就不拼接。

<!--
    獲取所有id值大於2的User對象
 -->
<select id="getUsersByIf" parameterType="int" resultType="User">
    select id, name, phone, email from users where 1=1
    <if test="_parameter != null">
        and id > #{_parameter}
    </if>
</select> 

測試代碼:

@Test
public void get1(){
    SqlSession session = MybatisUtils.getSession(false);
    List<User> userList = session.selectList("com.qcc.mapping.userMapper.getUsersByIf", 2);
    for (User user : userList) {
        System.out.println(user);
    }
}

運行結果:

User [id=3, name=cc, phone=13433333333, email=cc@126.com]
User [id=4, name=dd, phone=13444444444, email=dd@126.com]

在以上兩個示例當中,都是選取id, name, phone, email這四個字段,以下還會多次出現,實際開發當中選擇的字段更多,更復雜,浪費時間且容易寫錯,於是使用一個叫sql的標籤定義這些字段,只需要在使用的時候引入即可。

<sql id="columns">
    id, name, phone, email
</sql>

引入的寫法是:<include refid="columns"/>,它就相當於sqls標籤中id, name, phone, email


switch判斷

類似Java中的switch語法,在這裏使用的是choose…when…otherwise的語法
使用示例如下:

<!-- 
    與java中的switch(value)...case;break;...default格式類似,
    當when元素中的條件滿足的時候就拼接其中的內容到sql語句,同時就會跳出choose語句,
    即所有的when和otherwise條件中,只有一個會輸出,
    當所有條件都不滿足的時候就拼接otherwise中的內容。
    也就是說when和otherwise中的多個語句只會拼接上一個。所以這個語法用的不多。
 -->
<select id="getUser2" parameterType="User" resultType="User">
    select <include refid="columns"/> from users where 1=1
    <choose>
        <when test="id!=0">
            and id = #{id}
        </when>
        <when test="name!=null">
            and name = #{name}
        </when>
        <otherwise>
            and phone = #{phone}
        </otherwise>
    </choose>
</select>

測試代碼:

@Test
public void getUser2(){
    SqlSession session = MybatisUtils.getSession(false);
    User user = new User();
    user.setId(2);
    user.setName("aa");
    List<User> list = session.selectList("com.qcc.mapping.userMapper.getUser2", user);
    System.out.println(list);
}

運行結果:

[User [id=2, name=bb, phone=13422222222, email=bb@163.com]]

發現查詢出來的集合當中有一個User對象,對象的name屬性值是bb,而不是aa,這就驗證了有多個when條件成立的時候,它會自上往下執行拼接,一旦拼接上一個when中的語句後就不再繼續執行了,跳出choose語句。


where子句

where語句的作用主要是簡化SQL語句中where中的條件判斷的
上邊的if和switch的兩個示例中select標籤中寫的sql語句中,在where關鍵字後面都有個1=1,這個是必需的
如果沒有,拼接上對應的條件後sql語法就不正確了,多了個and,
沒有1=1時:select * from users where and id > #{_parameter}語法錯誤,多個and。
有了1=1後就是select * from users where 1=1 and id > #{_parameter}語法正確。
示例:

<!-- 
    1.where元素的作用是會在寫入where元素的地方輸出一個where2.where子句會自動把拼接後的語句中多餘的and去掉
    3.另外一個好處是你不需要考慮where元素裏面的條件輸出是什麼樣子的,MyBatis會智能的幫你處理,
        如果所有的條件都不滿足那麼MyBatis就會查出所有的記錄,
    4.如果輸出後是and開頭的,MyBatis會把第一個and忽略,當然如果是or開頭的,MyBatis也會把它忽略;
    5.where元素中你不需要考慮空格的問題,MyBatis會智能的幫你加上。
 -->
<select id="getUser3" parameterType="User" resultType="User">
    select <include refid="columns"/> from users
    <where>
        <if test="id!=0">
            and id = #{id}
        </if>
        <if test="name!=null">
            and name = #{name}
        </if>
    </where>
</select>

測試代碼:

@Test
public void getUser3(){
    SqlSession session = MybatisUtils.getSession(false);
    User user = new User();
    user.setId(2);
//  user.setName("aa");
    List<User> list = session.selectList("com.qcc.mapping.userMapper.getUser3", user);
    System.out.println(list);
}

測試結果:

[User [id=2, name=bb, phone=13422222222, email=bb@163.com]]

set子句

set子句一般更新數據庫記錄的操作
示例如下:

<!-- 
    set標籤的作用主要是在包含的語句前輸出一個set,
    然後如果包含的語句是以逗號結束的話將會把該逗號忽略,(即忽略賦值語句中最後一個,)
    如果set包含的內容爲空的話則會出錯。有了set元素我們就可以動態的更新那些修改了的字段。
 -->
<update id="update1" parameterType="User">
    update users
    <set>
        <if test="name != null">
            name = #{name},
        </if>
        <if test="phone != null">
            phone = #{phone},
        </if>
        <if test="email != null">
            email = #{email},
        </if>
    </set>
    where id = #{id}
</update>

測試代碼:

@Test
public void update1(){
    SqlSession session = MybatisUtils.getSession(true);//修改操作需要使用事務,提交事務
    User user = new User();
    user.setId(4);
    user.setName("update_4");
    user.setEmail("[email protected]");
    System.out.println("傳入的user對象:" + user);

    User user1 = session.selectOne("com.qcc.mapping.userMapper.getUser", 4);
    System.out.println("修改前:" + user1);

    /*用戶的電話號碼未重新賦值,則user的phone屬性爲null,因此保留不做修改*/
    session.update("com.qcc.mapping.userMapper.update1", user);

    //根據傳入的id查詢對應的實體對象,查詢修改後的user對象
    User user2 = session.selectOne("com.qcc.mapping.userMapper.getUser", 4);
    System.out.println("修改後:" + user2);
}

測試結果:

傳入的user對象:User [id=4, name=update_4, phone=null, [email protected]]
修改前:User [id=4, name=dd, phone=13444444444, email=dd@126.com]
修改後:User [id=4, name=update_4, phone=13444444444, [email protected]]

trim語法

trim添加需要的內容,去掉多餘的內容
trim元素的主要功能是可以在自己包含的內容前加上某些前綴,也可以在其後加上某些後綴,與之對應的屬性是prefix和suffix;
可以把包含內容的首部某些內容覆蓋,即忽略,也可以把尾部的某些內容覆蓋,對應的屬性是prefixOverrides和suffixOverrides;
正因爲trim有這樣的功能,所以我們也可以非常簡單的利用trim來代替where子句、set子句的功能,
語法格式如下:

<trim prefix="where" prefixOverrides="and |or ">
  <if ...>
    AND ...
  </if>
  <if ...>
    AND ...
  </if>
  <if ...>
    AND ...
  </if>
</trim>

它的作用是將生成的sql中添加 where 前綴,並將 sql 的 and 或者 or 前綴刪除掉
在更新操作時:

<trim prefix="set" suffixOverrides=",">
  <if ...>
    account = #{account},
  </if>
  <if ...>
    password = #{password},
  </if>
  <if ...>
    name = #{name},
  </if>
</trim>

它的作用是將生成的sql中添加 set 前綴,並將 sql 的 最後一個,後綴去掉
查詢時使用trim子句示例:

<select id="getUser4" parameterType="User" resultType="User">
    select <include refid="columns"/> from users
    <!-- 添加 where 關鍵字,去掉最前面的 and 關鍵字 -->
    <trim prefix="where" prefixOverrides="and">
        <if test="id != 0">
            and id = #{id}
        </if>
        <if test="name != null">
            and name = #{name}
        </if>
    </trim>
</select>

測試代碼:

@Test
public void getUser4(){
    SqlSession session = MybatisUtils.getSession(false);
    User user = new User();
//  user.setId(1);
    user.setName("aa");
    List<User> list = session.selectList("com.qcc.mapping.userMapper.getUser4", user);
    System.out.println(list);
}

測試結果:

[User [id=1, name=aa, phone=13411111111, email=aa@163.com]]

可見與使用where 語法的情況是一樣的。使用trim更新的操作類似,略。


foreach迭代變量

foreach的主要用在構建in條件中,它可以在SQL語句中進行迭代一個集合,比如批量刪除。也可以使用於比如批量插入操作。
foreach元素的屬性主要有item,index,collection,open,separator,close。

1、item表示集合中每一個元素進行迭代時的別名,
2、index指定一個名字,用於表示在迭代過程中,每次迭代到的位置,
3、open表示該語句以什麼開始,
4、separator表示在每次進行迭代之間以什麼符號作爲分隔符,
5、close表示以什麼結束,
6、collection屬性,該屬性是必須指定的,但是在不同情況下,該屬性的值是不一樣的,主要有一下3種情況:
    (1)如果傳入的是單參數且參數類型是一個List的時候,collection屬性值爲list
    (2)如果傳入的是單參數且參數類型是一個array數組的時候,collection的屬性值爲array
    (3)如果傳入的參數是多個的時候,我們就需要把它們封裝成一個Map了,當然單參數也可以封裝成map,
        實際上如果你在傳入參數的時候,在MyBatis裏面也是會把它封裝成一個Map的,map的key就是參數名,
        所以這個時候collection屬性值就是傳入的List或array對象在自己封裝的map裏面的key。

foreach示例1:使用在in條件中,批量刪除:

userMapper.xml 文件中映射 sql 的代碼如下:
<!-- 傳入數組ids進行批量刪除操作 -->
<delete id="delBatch">
    delete from users where id in
    <!--如果傳入的是單參數且參數類型是一個Array的時候,collection屬性值爲array-->
    <foreach collection="array" open="(" close=")" separator="," item="id">
        #{id}
    </foreach>
</delete>

測試代碼:(刪除前先查詢數據庫中的所有記錄並輸出,進行刪除操作後,再查詢數據庫中所有記錄並輸出)

@Test
public void delBatchDemo(){
    SqlSession session = MybatisUtils.getSession(true);
    /*查詢數據庫中所有記錄*/
    List<User> list = session.selectList("com.qcc.mapping.userMapper.getAll");
    System.out.println("刪除前:" + list);

    /*以下是批量刪除操作*/
    int[] ids = new int[]{1, 3, 4};
    int result = session.delete("com.qcc.mapping.userMapper.delBatch", ids);
    if(result>0){
        System.out.println("刪除" + result + "條記錄成功!");
    }else{
        System.out.println("刪除失敗!");
    }

    /*批量刪除操作完成後,再次查詢數據庫中所有記錄*/
    list = session.selectList("com.qcc.mapping.userMapper.getAll");
    System.out.println("刪除後:" + list);
}

測試結果:

刪除前:[User [id=1, name=aa, phone=13411111111, email=aa@163.com], User [id=2, name=bb, phone=13422222222, email=bb@163.com], User [id=3, name=cc, phone=13433333333, email=cc@126.com], User [id=4, name=update_4, phone=13444444444, [email protected]]]
刪除3條記錄成功!
刪除後:[User [id=2, name=bb, phone=13422222222, email=bb@163.com]]

foreach示例2:使用foreach執行批量插入操作:
userMapper.xml 文件中批量插入的映射 sql 的代碼如下:

<insert id="addBatchByList">
    insert into users(name, phone, email) values
    <!--如果傳入的是單參數且參數類型是一個List的時候,collection屬性值爲list-->
    <foreach item="user" collection="list" separator=",">
        (#{user.name}, #{user.phone}, #{user.email})
    </foreach>
</insert>

在User實體類中添加無參和帶參的構造方法,以便初始化User對象。

public User(String name, String phone, String email) {
    this.name = name;
    this.phone = phone;
    this.email = email;
}

public User() {}

批量插入的測試代碼如下:

@Test
public void addBatch(){
    List<User> userList = new ArrayList<>();
    User user1 = new User("關羽", "13333333333", "[email protected]");
    User user2 = new User("張飛", "13344444444", "[email protected]");
    User user3 = new User("趙雲", "13355555555", "[email protected]");
    User user4 = new User("黃忠", "13366666666", "[email protected]");
    userList.add(user1);
    userList.add(user2);
    userList.add(user3);
    userList.add(user4);
    SqlSession session = MybatisUtils.getSession(false);//傳入false,意味着不會自動提交事務,等批量操作完成後再提交事務。提升操作數據庫的效率。
    int result = session.insert("com.qcc.mapping.userMapper.addBatchByList", userList);
    if (result>0) {
        System.out.println("批量插入" + result + "條記錄成功!");
    } else {
        System.out.println("批量插入失敗!");
    }
    session.commit();//提交事務
    System.out.println("遍歷數據庫中所有的user信息");
    userList = session.selectList("com.qcc.mapping.userMapper.getAll");
    for (User user : userList) {
        System.out.println(user);
    }
}

批量插入的測試運行結果:

批量插入4條記錄成功!
遍歷數據庫中所有的user信息
User [id=2, name=bb, phone=13422222222, email=bb@163.com]
User [id=5, name=關羽, phone=13333333333, [email protected]]
User [id=6, name=張飛, phone=13344444444, [email protected]]
User [id=7, name=趙雲, phone=13355555555, [email protected]]
User [id=8, name=黃忠, phone=13366666666, [email protected]]

Mybatis動態sql常用的就以上這些了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章