mybatis 必備手冊(cè)

前言

  • 動(dòng)態(tài) SQL 是 MyBatis 的強(qiáng)大特性之一。如果你使用過 JDBC 或其它類似的框架,你應(yīng)該能理解根據(jù)不同條件拼接 SQL 語句有多痛苦,例如拼接時(shí)要確保不能忘記添加必要的空格景馁,還要注意去掉列表最后一個(gè)列名的逗號(hào)萧诫。利用動(dòng)態(tài) SQL斥难,可以徹底擺脫這種痛苦。

  • 使用動(dòng)態(tài) SQL 并非一件易事帘饶,但借助可用于任何 SQL 映射語句中的強(qiáng)大的動(dòng)態(tài) SQL 語言哑诊,MyBatis 顯著地提升了這一特性的易用性。

  • 這篇文章總結(jié)了日常的增刪改查及刻,重點(diǎn)關(guān)注@Param的注解以及批量操作相關(guān)動(dòng)作镀裤。

  • 這篇文章總結(jié)了比較通用的自定義SQL的語法,包含的標(biāo)簽包含if缴饭、choose (when, otherwise)暑劝、trim (where, set)、foreach等颗搂。


準(zhǔn)備

CREATE TABLE `t_student` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(255) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年齡',
  `clazz_id` int(11) DEFAULT NULL COMMENT '班級(jí)id',
  `number` varchar(6) DEFAULT NULL COMMENT '學(xué)號(hào)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC


public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Integer clazzId;
    private String number;
}
  • 前置準(zhǔn)備的數(shù)據(jù)庫表字段和對(duì)應(yīng)的類對(duì)象定義担猛。


常用SQL

select語句

  <sql id="base_columns">
    id, name, age, clazz_id, number
  </sql>

  <select id="selectById" resultMap="BaseResultMap">
    select <include refid="base_columns"/> from t_student where id = #{id}
  </select>

  Student selectById(@Param("id") int id);
  • 根據(jù)單個(gè)id進(jìn)行查詢的例子。


  <sql id="base_columns">
    id, name, age, clazz_id, number
  </sql>

  <select id="selectByIds" resultMap="BaseResultMap">
    SELECT <include refid="base_columns"/> from t_student where id in
    <foreach collection="ids" separator="," item="id" open="(" close=")">
      #{id}
    </foreach>
    AND age=#{age}
  </select>

  List<Student> selectByIds(@Param("ids") List<Integer> idList, @Param("age") Integer age);
  • 根據(jù)多個(gè)ids進(jìn)行查詢例子丢氢,前提是保證ids不為空傅联。


  <sql id="base_columns">
    id, name, age, clazz_id, number
  </sql>

  <select id="selectByIdsV2" resultMap="BaseResultMap">
    SELECT <include refid="base_columns"/> from t_student
    <where>
      <if test="ids != null and ids.size() > 0">
        id in
        <foreach collection="ids" open="(" close=")" separator=",">
          #{id}
        </foreach>
      </if>
      <if test="age != null">
        AND age = #{age}
      </if>
    </where>
  </select>

  List<Student> selectByIdsV2(@Param("ids") List<Integer> idList, @Param("age") Integer age);
  • <foreach>的collection等價(jià)于@Param注解的變量,如例子中的ids疚察。
  • 通過<where>注解解決idList為空的場(chǎng)景蒸走。
  • where 元素只會(huì)在子元素返回任何內(nèi)容的情況下才插入 “WHERE” 子句。而且貌嫡,若子句的開頭為 “AND” 或 “OR”载碌,where 元素也會(huì)將它們?nèi)コ?/li>


  <sql id="base_columns">
    id, name, age, clazz_id, number
  </sql>

  <select id="selectByIdsV3" resultMap="BaseResultMap">
    SELECT <include refid="base_columns"/> from t_student
    <where>
      <if test="studentList != null and studentList.size() > 0">
        id in
        <foreach collection="studentList" item="item" open="(" close=")" separator=",">
          #{item.id}
        </foreach>
      </if>
      <if test="age != null">
        AND age = #{age}
      </if>
    </where>
  </select>

  List<Student> selectByIdsV3(@Param("studentList") List<Student> studentList, @Param("age") Integer age);
  • <foreach>的collection等價(jià)于@Param注解的變量,如例子中的studentList衅枫。
  • 通過<where>注解解決studentList為空的場(chǎng)景。
  • where 元素只會(huì)在子元素返回任何內(nèi)容的情況下才插入 “WHERE” 子句朗伶。而且弦撩,若子句的開頭為 “AND” 或 “OR”,where 元素也會(huì)將它們?nèi)コ?/li>


  <sql id="base_columns">
    id, name, age, clazz_id, number
  </sql>

  <select id="selectByIdsV4" resultMap="BaseResultMap">
    SELECT <include refid="base_columns"/> from t_student
    <trim prefix="where" prefixOverrides="and|or">
      <if test="studentList != null and studentList.size() > 0">
        id in
        <foreach collection="studentList" item="item" open="(" close=")" separator=",">
          #{item.id}
        </foreach>
      </if>
      <if test="age != null">
        AND age = #{age}
      </if>
    </trim>
  </select>

  List<Student> selectByIdsV4(@Param("studentList") List<Student> studentList, @Param("age") Integer age);
  • 過自定義 trim 元素來定制 where 元素的功能论皆。
  • prefix 屬性中指定前置插入的內(nèi)容
  • prefixOverrides 屬性會(huì)忽略前置的通過管道符分隔的文本序列益楼。
  • suffix 屬性中指定后置插入的內(nèi)容
  • suffixOverrides屬性會(huì)忽略后置的通過管道符分隔的文本序列。


insert語句

    <insert id="insertV1" parameterType="com.example.model.Student" keyProperty="id" useGeneratedKeys="true">
      insert into t_student (`name`, age, clazz_id, `number`)
      values (#{name}, #{age}, #{clazzId}, #{number})
    </insert>

    Integer insertV1(Student student);
  • 通用的插入單個(gè)對(duì)象的例子点晴。


    <insert id="insertV2" parameterType="com.example.model.Student" keyProperty="id" useGeneratedKeys="true">
        insert into t_student (`name`, age, clazz_id, `number`)
        values (#{student.name}, #{student.age}, #{student.clazzId}, #{student.number})
    </insert>

    Integer insertV2(@Param("student") Student student);
  • 通過@param指定別名student來進(jìn)行單個(gè)對(duì)象的插入感凤。


  <insert id="batchInsertV1">
    insert into t_student (`name`, age, clazz_id, `number`)
    values
    <foreach collection="list" item="item" separator=",">
      (#{item.name}, #{item.age}, #{item.clazzId}, #{item.number})
    </foreach>
  </insert>

  Integer batchInsertV1(List<Student> studentList);
  • 批量插入多個(gè)對(duì)象的例子,沒有指定別名通用的collection是list粒督,注意foreach沒有open和close屬性陪竿。


  <insert id="batchInsertV2">
    insert into t_student (`name`, age, clazz_id, `number`)
    values
    <foreach collection="studentList" item="item" separator=",">
      (#{item.name}, #{item.age}, #{item.clazzId}, #{item.number})
    </foreach>
  </insert>

  Integer batchInsertV2(@Param("studentList") List<Student> studentList);
  • 批量插入多個(gè)對(duì)象的例子,通過@Param指定別名studentList屠橄,對(duì)應(yīng)的collection為別名變量族跛。


delete語句

  <delete id="deleteById" parameterType="java.lang.Integer">
    delete from t_student where id = #{id}
  </delete>

  int deleteById(@Param("id") int id);
  • 通用的單個(gè)對(duì)象的刪除例子闰挡。


  <delete id="batchDetele">
    delete from t_student
    <if test="idList != null and idList.size() > 0">
        where id in
        <foreach collection="idList" item="item" separator="," open="(" close=")">
            #{item}
        </foreach>
    </if>
  </delete>

  int batchDetele(@Param("idList") List<Integer> idList);
  • 批量刪除的例子,通過@Param執(zhí)行別名idList礁哄,注意<foreach>在這種場(chǎng)景指定open和close對(duì)應(yīng)的值长酗。


update語句

    <update id="updateV1" parameterType="com.example.model.Student">
        update t_student
        <set>
            <if test="name != null">`name` = #{name},</if>
            <if test="age != null" >age = #{age},</if>
            <if test="clazzId != null">clazzId = #{clazzId},</if>
            <if test="number != null">`number` = #{number}</if>
        </set>
        where id = #{id}
    </update>

    Integer updateV1(Student student);
  • 用于動(dòng)態(tài)更新語句的類似解決方案叫做 set。
  • set 元素可以用于動(dòng)態(tài)包含需要更新的列桐绒,忽略其它不更新的列夺脾。
  • set 元素會(huì)動(dòng)態(tài)地在行首插入 SET 關(guān)鍵字,并會(huì)刪掉額外的逗號(hào)(這些逗號(hào)是在使用條件語句給列賦值時(shí)引入的)茉继。


    <update id="updateV2" parameterType="com.example.model.Student">
        update t_student
        <trim prefix="set" suffixOverrides=",">
            <if test="name != null">`name` = #{name},</if>
            <if test="age != null" >age = #{age},</if>
            <if test="clazzId != null">clazzId = #{clazzId},</if>
            <if test="number != null">`number` = #{number},</if>
        </trim>
        where id = #{id}
    </update>

    Integer updateV2(Student student);
  • 通過自定義 trim 元素來實(shí)現(xiàn)等價(jià)的set操作咧叭。


    <update id="batchUpdate" parameterType="java.util.List">
        update t_student
        <trim prefix="set" suffixOverrides=",">

          <trim prefix="name = case " suffix="end,">
            <foreach collection="studentList" item="item">
              <if test="item.name != null">
                  when id = #{item.id} then #{item.name}
              </if>
            </foreach>
          </trim>

          <trim prefix="age = case " suffix="end,">
              <foreach collection="studentList" item="item">
                  <if test="item.age != null">
                      when id = #{item.id} then #{item.age}
                  </if>
              </foreach>
          </trim>

          <trim prefix="clazzId = case " suffix="end,">
              <foreach collection="studentList" item="item">
                  <if test="item.clazzId != null">
                      when id = #{item.id} then #{item.clazzId}
                  </if>
              </foreach>
          </trim>

          <trim prefix="number = case " suffix="end,">
              <foreach collection="studentList" item="item">
                  <if test="item.number != null">
                      when id = #{item.id} then #{item.number}
                  </if>
              </foreach>
          </trim>
        </trim>

        where id in
        <foreach collection="studentList" item="item" open="(" close=")" separator=",">
            #{item.id}
        </foreach>
    </update>

    Integer batchUpdate(@Param("studentList") List<Student> studentList);
  • 通過自定義trim標(biāo)簽來實(shí)現(xiàn)批量更新操作。


參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末馒疹,一起剝皮案震驚了整個(gè)濱河市佳簸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颖变,老刑警劉巖生均,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異腥刹,居然都是意外死亡马胧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門衔峰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佩脊,“玉大人,你說我怎么就攤上這事垫卤⊥茫” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵穴肘,是天一觀的道長(zhǎng)歇盼。 經(jīng)常有香客問我,道長(zhǎng)评抚,這世上最難降的妖魔是什么豹缀? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮慨代,結(jié)果婚禮上邢笙,老公的妹妹穿的比我還像新娘。我一直安慰自己侍匙,他們只是感情好氮惯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般筐骇。 火紅的嫁衣襯著肌膚如雪债鸡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天铛纬,我揣著相機(jī)與錄音厌均,去河邊找鬼。 笑死告唆,一個(gè)胖子當(dāng)著我的面吹牛棺弊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播擒悬,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼模她,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了懂牧?” 一聲冷哼從身側(cè)響起侈净,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎僧凤,沒想到半個(gè)月后畜侦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡躯保,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年旋膳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片途事。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡验懊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尸变,到底是詐尸還是另有隱情义图,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布召烂,位于F島的核電站歌溉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏骑晶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一草慧、第九天 我趴在偏房一處隱蔽的房頂上張望桶蛔。 院中可真熱鬧,春花似錦漫谷、人聲如沸仔雷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽碟婆。三九已至电抚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間竖共,已是汗流浹背蝙叛。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留公给,地道東北人借帘。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像淌铐,于是被迫代替她去往敵國和親肺然。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容