MyBatis 入門筆記+理解(二)

這是基于b站狂神的JavaWeb課程的筆記 課程鏈接
筆記第一部分鏈接:MyBatis 入門筆記+理解(一)

9. 復(fù)雜查詢之多對一

9.1 環(huán)境搭建

  • sql建表
CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, 秦老師); 

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (1, 小明, 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, 小紅, 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, 小張, 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, 小李, 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, 小王, 1);
  • 構(gòu)造實體類

學(xué)生

@Data
public class Student {
    private int id;
    private String name;
    // 學(xué)生需要關(guān)聯(lián)一個老師
    private Teacher teacher;
}

老師

@Data
public class Teacher {
    private int id;
    private String name;
}

9.2 多對一

  • 現(xiàn)有需求:獲取所有學(xué)生的信息和他們關(guān)聯(lián)的老師的信息
    多名學(xué)生和一個老師關(guān)聯(lián)
    需求對應(yīng)的sql語句:
select s.id,s.name,t.id,t.name 
from student s, teacher t 
where s.tid = t.id;
  • 思路:
    1. 查詢出所有學(xué)生的信息
    2. 根據(jù)查出來學(xué)生的tid,查詢出對應(yīng)關(guān)聯(lián)的老師的信息
  • 根據(jù)思路編寫Mapper.xml:
    方法一:根據(jù)查詢嵌套處理
    <!--  根據(jù)查詢嵌套處理  -->
    <!--  1. 查詢所有學(xué)生信息  -->
    <select id="getStudents" resultMap="studentAndTeacher">
        select * from student
    </select>

    <!--  兩次查詢用一個resultMap關(guān)聯(lián)起來  -->
    <resultMap id="studentAndTeacher" type="student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--
            復(fù)雜的屬性,單獨處理:對象用association垮抗,集合用collection
            屬性是一個對象陆盘,所以先用javaType來規(guī)定是哪個類
            而從表中獲得的是一個tid,所以需要用一個字查詢語句恤磷,用tid獲取整個Teacher對象
            select="getTeachers"就規(guī)定了用如下的這個sql去獲得teacher的信息
        -->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeachers"/>
    </resultMap>

    <!--  2. 根據(jù)學(xué)生查出來的tid面哼,查詢對應(yīng)的老師! (子查詢)  -->
    <select id="getTeachers" resultType="teacher">
        select * from teacher where id=#{tid}
    </select>
  • 本質(zhì)上碗殷,第一個 <select>select * from student 得到的表字段為 tid 而學(xué)生類的屬性為 teacher精绎,所以需要一個結(jié)果集映射將他們對應(yīng)起來
  • 而恰好 teacher 是一個對象 (用 javaType="Teacher" 表示),不能簡單地只將名稱進行映射锌妻,還需要得到 teacher 的內(nèi)部屬性信息代乃,所以我們又需要一個子查詢,就是第二個 <select> 中的sql查詢仿粹。

方法二:根據(jù)結(jié)果嵌套處理

    <!--  根據(jù)結(jié)果嵌套處理  -->
    <select id="getStudents2" resultMap="mapTeacher">
        select s.id sid, s.name sname, t.id tid, t.name tname
        from student s, teacher t
        where s.tid = t.id
    </select>

    <resultMap id="mapTeacher" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <!--     
                根據(jù)查詢到的結(jié)果(tid, tname),
                來與Teacher這個類中的屬性進行映射
            -->
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>
    </resultMap>

10. 復(fù)雜查詢之一對多

與9中的情況相對應(yīng)搁吓,一個老師擁有多個學(xué)生,此時稱為一對多

11.1 環(huán)境搭建

  • 表與9中相同
  • 實體類
    老師
@Data
public class Teacher {
    private int id;
    private String name;
    // 一個老師擁有多個學(xué)生
    private List<Student> students;
}

學(xué)生

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}

10.2 一對多處理

  • 需求:根據(jù)id查詢老師信息和這個老師擁有的所有學(xué)生信息
  • sql:
select t.id tid, t.name tname, s.id sid, s.name sname
from student s, teacher t 
where t.id = s.tid and t.id = #{tid}
  • 接口:
public interface TeacherMapper {

    // 根據(jù)id查詢老師信息和這個老師擁有的所有學(xué)生信息
    // 使用@param("tid")后吭历,則Mapper.xml中的sql語句中應(yīng)用對應(yīng)的#{tid}
    // 提取該參數(shù)
    Teacher getTeacher(@Param("tid") int id);
}

方法一:根據(jù)結(jié)果嵌套處理

    <!--  根據(jù)結(jié)果嵌套處理  -->
    <select id="getTeacher" resultMap="tsMap">
        select t.id tid, t.name tname, s.id sid, s.name sname
        from student s, teacher t 
        where t.id = s.tid and t.id = #{tid}
    </select>
    
    <resultMap id="tsMap" type="teacher">
        <!--    名稱映射    -->
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--
            屬性為集合時 ==> collection
            集合中的泛型用 ofType 規(guī)定
        -->
        <collection property="students" ofType="student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
        </collection>
    </resultMap>
  • 先拿到結(jié)果 t.id tid, t.name tname, s.id sid, s.name sname
  • 再用拿到的這些結(jié)果與老師的屬性堕仔,以及老師擁有的學(xué)生的屬性作一一映射

方法二:根據(jù)查詢嵌套處理

    <!--  根據(jù)查詢嵌套處理  -->
    <!--  先根據(jù)id拿到老師  -->
    <select id="getTeacher2" resultMap="tsMap2">
        select * from teacher
        where id = #{tid}
    </select>

    <resultMap id="tsMap2" type="teacher">
        <!--  
            注意:這里即使名稱相同,也要顯式地映射一次
            因為column中的id在下面被映射給了"students"
            這里不映射會導(dǎo)致查不到teacher的id
        -->
        <result property="id" column="id"/>
        <!--
            屬性名稱為students
            類為Arraylist晌区,集合中的泛型為student
            再用一個子查詢?nèi)ゲ閠id為"id"的學(xué)生
        -->
        <collection property="students" javaType="Arraylist" ofType="student" column="id" select="getStudent"/>
    </resultMap>

    <!--  再根據(jù)老師的id拿到tid為老師的id的學(xué)生  -->
    <select id="getStudent" resultType="student">
        select * from student
        where tid = #{id}
    </select>

11. 動態(tài)SQL

  • 減少了根據(jù)不同條件拼接 SQL 語句的痛苦

11.1 If

一個官方文檔中的例子足矣:

<select id="findActiveBlogWithTitleLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

一般將一個 Map 作為參數(shù)摩骨,若在 Map 中放入了 title 的值,則可以被取出并放到 <if> 中的 AND 語句里

11.2 Choose

與Java中的 switch 類似:

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

根據(jù) <when> 的編寫順序查看是否滿足條件朗若,只會執(zhí)行第一條滿足條件的 <when> 恼五,若沒有滿足條件的則執(zhí)行 <otherwise>

11.3 Where, Set, Trim

Where
<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

官方doc一句話:

where 元素只會在子元素返回任何內(nèi)容的情況下才插入 “WHERE” 子句。而且哭懈,若子句的開頭為 “AND” 或 “OR”灾馒,where 元素也會將它們?nèi)コ?/p>

也就是說在上面這個例子中,若沒有一個 if 被滿足遣总,where將自動消失睬罗,若只有第二個 if 或 只有第三個 if 被滿足,他們前面的 AND 將自動消失旭斥。

Set
<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

這個例子中容达,set 元素會動態(tài)地在行首插入 SET 關(guān)鍵字,并會刪掉額外的逗號

trim

可自定義 where

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

也可自定義 set

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

11.4 foreach

需求的SQL:

SELECT * FROM user 
WHERE gender = 'male'
AND ( id = 1 OR id = 2 OR id = 4 )
  • 在接口的參數(shù)中使用 Map<String, Object>() map
  • 在map中添加一個list
ArrayList<Integer> ids = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
map.put("ids", ids)

在mapper.xml中編寫

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM user
  WHERE Gender = #{male}
  <foreach item="id" collection="ids"
      open=" AND (" separator="OR" close=")">
        #{id}
  </foreach>
</select>

12. 緩存

12.1 一級緩存

  • 默認開啟
  • Sqlsession 級別的緩存
  • 通俗地說垂券,一級緩存只存在于其對應(yīng)的一個 Sqlsession 的生命周期中:
// 對于這個sqlSession的緩存董饰,只存在于這兩行代碼之間
SqlSession sqlSession = MyBatisUtils.getSqlSession();
...
sqlSession.close()
  • 在一個 sqlSession 中,查詢同一個東西,只會在第一次查詢那個東西時連接到數(shù)據(jù)庫卒暂,之后都會直接從緩存中拿去
  • 有任何增啄栓、刪、改的操作都會清除緩存
  • sqlSession.clearCache() 也可手動清除緩存
  • 一級緩存就是一個Map

12.2 二級緩存

  • 基于 namespace 級別的緩存
  • 需手動開啟
    <!-- 顯式地開啟全局緩存>
    <setting name="cacheEnabled" value="true"/>
    
    <!-- 在當(dāng)前Mapper.xml中使用二級緩存 -->
    <cache/>
    
    也可以自定義參數(shù)
    <cache
    eviction="FIFO"
    flushInterval="60000"
    size="512"
    readOnly="true"/>
    
  • 開啟后也祠,當(dāng)一個會話結(jié)束了昙楚,其對應(yīng)的緩存在消失之前會進入到二級緩存,也就是當(dāng)前Mapper的緩存中

12.3 查看緩存的順序

在一次會話中做一次查詢

  1. 先查看當(dāng)前Mapper中的二級緩存中有沒有查詢結(jié)果诈嘿,若沒有
  2. 再查看當(dāng)前會話對應(yīng)的一級緩存中有沒有堪旧,若沒有
  3. 查詢數(shù)據(jù)庫
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市奖亚,隨后出現(xiàn)的幾起案子淳梦,更是在濱河造成了極大的恐慌,老刑警劉巖昔字,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爆袍,死亡現(xiàn)場離奇詭異,居然都是意外死亡作郭,警方通過查閱死者的電腦和手機陨囊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夹攒,“玉大人蜘醋,你說我怎么就攤上這事∮匠ⅲ” “怎么了压语?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長编检。 經(jīng)常有香客問我无蜂,道長,這世上最難降的妖魔是什么蒙谓? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮训桶,結(jié)果婚禮上累驮,老公的妹妹穿的比我還像新娘。我一直安慰自己舵揭,他們只是感情好谤专,可當(dāng)我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著午绳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜡坊,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天杠输,我揣著相機與錄音,去河邊找鬼蠢甲。 笑死,一個胖子當(dāng)著我的面吹牛曼追,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播射亏,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贡茅,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎合砂,沒想到半個月后缘屹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轻姿,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡溺森,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年渣聚,在試婚紗的時候發(fā)現(xiàn)自己被綠了症歇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缩幸。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖氧猬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烫沙,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布隙笆,位于F島的核電站锌蓄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏撑柔。R本人自食惡果不足惜瘸爽,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铅忿。 院中可真熱鬧剪决,春花似錦、人聲如沸檀训。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽峻凫。三九已至渗鬼,卻和暖如春梢薪,著一層夾襖步出監(jiān)牢的瞬間何荚,已是汗流浹背悴品。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工咧栗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霸褒。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓仓犬,卻偏偏與公主長得像侠驯,于是被迫代替她去往敵國和親脐恩。 傳聞我的和親對象是個殘疾皇子镐侯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,947評論 2 355

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

  • 1.JDBC有哪些不足,MyBatis是如何解決的① 數(shù)據(jù)庫鏈接創(chuàng)建驶冒、釋放頻繁造成系統(tǒng)資源浪費從而影響系統(tǒng)性能苟翻,如...
    機智的檸檬閱讀 374評論 0 0
  • 這是學(xué)習(xí)顏群老師的mybatis教程[https://www.bilibili.com/video/BV1gs41...
    wangailiu閱讀 398評論 0 0
  • 1搭伤、什么是Mybatis? (1)Mybatis是一個半ORM(對象關(guān)系映射)框架袜瞬,它內(nèi)部封裝了JDBC,開發(fā)時只...
    青青子衿zq閱讀 117評論 0 0
  • 1身堡、MyBatis簡介 MyBatis 是一款優(yōu)秀的持久層框架 中文官網(wǎng):https://mybatis.org/...
    CHeng_c0e9閱讀 408評論 0 0
  • 1 Mybatis入門 1.1 單獨使用jdbc編程問題總結(jié) 1.1.1 jdbc程序 上邊使...
    哇哈哈E閱讀 3,307評論 0 38