1. 程式人生 > >spring boot整合mybatis基於註解開發以及動態sql的使用

spring boot整合mybatis基於註解開發以及動態sql的使用

  讓我們回憶一下上篇部落格中mybatis是怎樣發揮它的作用的,主要是三類檔案,第一mapper介面,第二xml檔案,第三全域性配置檔案(application.properties),而今天我們就是來簡化mybatis的工作的——利用註解替代xml配置檔案。

  先貼出mapper介面程式碼

@Mapper
public
interface UserMapper { //獲取使用者名稱單 public List<User> getUser() throws Exception; //根據id刪除使用者 public void deleteUser(int
id)throws Exception; //新增使用者 public void addUser(User user)throws Exception; //修改使用者資訊 public void updateUser(User user) throws Exception; }

相較於上次的程式碼新增了一個修改使用者資訊的介面,然而怎麼做才能替代xml呢???

針對以上的增刪改查的操作,有四個註解@Select、@Delete、@Insert、@Update,在註解中加上之前在xml中寫的sql就行了,所以完整的mapper介面檔案如下

@Mapper
public
interface UserMapper { //獲取使用者名稱單 @Select("select * from user") public List<User> getUser() throws Exception; //根據id刪除使用者 @Delete("delete from user where id = #{id}") public void deleteUser(int id)throws Exception; //新增使用者 @Insert("insert into user(id,username,age)values(#{id},#{username},#{age})")
public void addUser(User user)throws Exception; //修改使用者資訊 @Update("update user set username = #{name} where id = #{id}") public void updateUser(User user) throws Exception; }

 剩下的service和controller中的程式碼很簡單,和xml開發中的寫法保持一致。需要值得注意的是不要忘記在各個介面和類中類名前的位置加上對應的註解,@Mapper、@Service、@Component等,不然spring是掃描不到的。這裡有個小技巧,如果在啟動類中加上註解@MapperScan(“com.XX.dao”),即可以省去@Mapper註解

說完了註解的開發我們來看一下這樣的需求,如果我們要往資料庫中更新一個物件,前臺傳過來的物件中有幾個屬性沒有賦值,所以我們controller接收時就會將這幾個屬性置空,而我們需要更新不為空的屬性,這時該怎麼辦??當然可以在service中將這個物件處理後再更新到資料庫中,但是其實動態sql就可以直接解決這個問題。首先將問題分個類

if+set/where

例如現在前臺將這樣一個物件傳過來

{
    "id":1,
    "age":12
}

我控制器的方法為

  //更新使用者
    public String updateUser(User user)throws Exception{
        userService.updateUser(user);
        return "id為"+user.getId()+"的使用者更新了";
    }

如果我直接更新到後臺顯然會把這條記錄之前的使用者名稱給覆蓋為空(在資料庫允許該欄位為空的情況下),所以看直接來看我的動態sql程式碼

    <update id="updateUser" parameterType="com.fc.pojo.User">
        update user set        
            <if test = "username != null">
                user.username = #{username},
            </if>
            <if test = "age != 0">
                user.age = #{age}
            </if>
            where id = #{id}
</update>

這樣的sql拼接程式碼看起來很簡單,但是有一個問題,如果age屬性為0(前臺如果不傳age屬性的話預設賦值為0)的話,最終sql語句會變成 update user set user.username =?,where id = ?

這樣顯然也是不對的,所以mybatis為我們提供了<set></set>標籤將多餘的逗號去掉,所以最終的動態sql變成

<update id="updateUser" parameterType="com.fc.pojo.User">
        update user 
            <set>
                <if test = "username != null">
                    user.username = #{username},
                </if>
                <if test = "age != 0">
                    user.age = #{age}
                </if>
            </set>    
            where id = #{id}
    </update>

這樣就解決了我們的問題了。同理在select語句中,也有這樣的問題

<select id="getUser" parameterType="com.fc.pojo.User" resultType="com.fc.pojo.User">
        select * from user where    
         <if test="username != null">
           username=#{username}
        </if>
         
        <if test="age!= null">
           and age=#{age}
        </if>
   </select>

如果age為空的話sql就變成了select * from user where and age=?,所以要加上<where></where>標籤,這樣改進後的xml就是

    <select id="getUser" parameterType="com.fc.pojo.User" resultType="com.fc.pojo.User">
        select * from user 
        <where>
         <if test="username != null">
           username=#{username}
        </if>
         
        <if test="age!= null">
           and age=#{age}
        </if>
        </where>
    </select>

foreach

我們在開發的時候經常會遇到這樣的需求,刪除多個物件,前臺直接傳一個物件id的集合,這個時候常規的做法是對集合處理,將id拿出來一個個刪掉,其實也可以將集合放入一個包裝類中,直接把包裝類作為parameterType傳入xml中,在xml中處理id集合。下面是包裝類,我加上了陣列的方式,不僅是id集合,還有id陣列,都可以用這種方法來做

public class UserVo {
  private List<Integer>idList;//id集合
  private int[]idArray;       //id陣列
  public List<Integer> getIdList() {
    return idList;
  }
  public void setIdList(List<Integer> idList) {
    this.idList = idList;
  }
  public int[] getIdArray() {
    return idArray;
  }
  public void setIdArray(int[] idArray) {
    this.idArray = idArray;
  }
  
}

而xml檔案中要使用foreach標籤,在el表示式中和js中好像都有類似的用法,用來做迴圈操作,需要注意的是collection的值應該和包裝類中的屬性名保持一致。具體程式碼如下

<!-- 以id集合刪除使用者 -->
    <delete id="deleteByIdList" parameterType="com.fc.pojo.UserVo">
        delete from user
        where id in
        <foreach item="id" collection="idList" open="(" separator="," close=")">
         #{id}
        </foreach>
    </delete>
    <!-- 以id陣列刪除使用者 -->
    <delete id="deleteByIdArray" parameterType="com.fc.pojo.UserVo">
        delete from user
        where id in
        <foreach item="id" collection="idArray" open="(" separator="," close=")">
         #{id}
        </foreach>
    </delete>

然後是Controller程式碼

    //刪除id集合
    @RequestMapping(value="deleteByIdList",method=RequestMethod.DELETE)
    public String deleteByIdList(@RequestBody UserVo userVo)throws Exception{
      userService.deleteByIdList(userVo);
      return "id列表裡的使用者都刪掉了";
    }
     //刪除id陣列
    @RequestMapping(value="deleteByIdArray",method=RequestMethod.DELETE)
    public String deleteByIdArray(@RequestBody UserVo userVo)throws Exception{
      userService.deleteByIdArray(userVo);
      return "id數組裡的使用者都刪掉了";
    }

mapper介面和service的程式碼我就不貼了,套路跟之前都是一樣的

最後是用來測試的json,第一個是測陣列的,第二個測集合的

{
    "idArray":[1,2,3]  
}
{
    "idList":[1,2,3]
}

sql片段

sql片段就是將一段重複率較高的sql抽取出來,供別的sql呼叫,這樣可以有效地提高程式碼的複用率,話不多說,比如我們在新增一個使用者時需要返回新增使用者id,而我們之前的程式碼中已經有新增使用者的sql,重複寫一遍顯得多此一舉了,就可以把插入語句抽取出來供多次呼叫,程式碼如下,為了看到效果,我把之前的新增使用者的語句也使用呼叫sql片段的方法來做

<sql id="base_insert_sql" >
        insert into user(id,username,age)values(#{id},#{username},#{age})
    </sql>
    <!-- 新增使用者 -->
    <insert id="addUser" parameterType="com.fc.pojo.User">
        <include refid="base_insert_sql" />
    </insert>
    <!-- 新增使用者,返回使用者id -->
    <insert id="addUserWithId" parameterType="com.fc.pojo.User">
        <selectKey keyProperty="id" resultType="int">  
            select LAST_INSERT_ID()  
        </selectKey> 
        <include refid="base_insert_sql" />
    </insert>

好了,我在開發中常用到的動態sql就這些了,然後把以上xml檔案轉為註解的方法我就懶得去做了,有空再補上,最後安利一款測試軟體Postman,挺好用的,公司也在用這個,以上的所有程式碼都是我用PostMan測試通過的,畢竟瀏覽器也發不了post和delete請求,所以嗯。。。就醬。