Mybatis 小談 (下篇)
寫在前面:分享技術,共同進步,有不足請見諒,相關意見可評論告知 ~
程式設計路漫之遠兮,運架構體之帷幄;
勸君專注案前事,亦是杯酒敬蒼生;
目錄
多對一處理
測試環境搭建
-
匯入lombok
-
新建實體類 Teacher,Student
-
建立Mapper介面
-
建立Mapper.XML檔案
-
在核心配置檔案中繫結註冊我們的Mapper介面或者檔案!【方式很多,隨心選】
-
測試查詢是否能夠成功!
搭建圖解:
原始資料庫SQL 操作:
按照查詢巢狀處理
解決兩個內容無法連線的問題(即有一個屬性為空)
<!-- 思路: 1. 查詢所有的學生資訊 2. 根據查詢出來的學生的tid,尋找對應的老師! 子查詢 --> <select id="getStudent" resultMap="StudentTeacher"> select * from student </select> <resultMap id="StudentTeacher" type="Student"> <result property="id" column="id"/> <result property="name" column="name"/> <!--複雜的屬性,我們需要單獨處理 物件: association 集合: collection --> <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/> </resultMap> <select id="getTeacher" resultType="Teacher"> select * from teacher where id = #{id} </select>
按照結果巢狀處理(推薦)
<!--按照結果巢狀處理--> <select id="getStudent2" resultMap="StudentTeacher2"> select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid = t.id; </select> <resultMap id="StudentTeacher2" type="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <association property="teacher" javaType="Teacher"> <result property="name" column="tname"/> </association> </resultMap>
回顧Mysql 多對一查詢方式:
- 子查詢
- 聯表查詢
一對多處理
前序:一對多關係一般都由多端維護系統關係
環境搭建
同上
實體類
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
//一個老師擁有多個學生
private List<Student> students;
}
按照結果巢狀處理
<!--按結果巢狀查詢-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname, t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--複雜的屬性,我們需要單獨處理 物件: association 集合: collection
javaType="" 指定屬性的型別!
集合中的泛型資訊,我們使用ofType獲取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
按照查詢巢狀處理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from mybatis.student where tid = #{tid}
</select>
小結
- 關聯 - association 【多對一】
- 集合 - collection 【一對多】
- javaType & ofType
- JavaType 用來指定實體類中屬性的型別
- ofType 用來指定對映到List或者集合中的 pojo型別,泛型中的約束型別!
注意點:
- 保證SQL的可讀性,儘量保證通俗易懂
- 注意一對多和多對一中,屬性名和欄位的問題!
- 如果問題不好排查錯誤,可以使用日誌 , 建議使用 Log4j
動態 SQL
什麼是動態SQL:動態SQL就是指根據不同的條件生成不同的SQL語句
動態 SQL 元素和 JSTL 或基於類似 XML 的文字處理器相似MyBatis 採用功能強大的基於 OGNL 的表示式來淘汰其它大部分元素。
if
choose (when, otherwise)
trim (where, set)
foreach
搭建環境
CREATE TABLE `blog` (
`id` varchar(50) NOT NULL COMMENT '部落格id',
`title` varchar(100) NOT NULL COMMENT '部落格標題',
`author` varchar(30) NOT NULL COMMENT '部落格作者',
`create_time` datetime NOT NULL COMMENT '建立時間',
`views` int(30) NOT NULL COMMENT '瀏覽量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
建立一個基礎工程
-
導包
-
編寫配置檔案
-
編寫實體類
@Data public class Blog { private int id; private String title; private String author; private Date createTime; private int views; }
-
編寫實體類對應Mapper介面 和 Mapper.XML檔案
Tips:解決Idea拼寫不符合規範問題(波浪線提示)
@SuppressWarnings("all")
編寫隨機ID工具類
配置資料庫欄位名與實體類中的相容問題
利用駝峰式命名解決
IF
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
choose (when, otherwise)
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
類似於 switch....case
trim (where,set)
select * from mybatis.blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
所謂的動態SQL,本質還是SQL語句 , 只是我們可以在SQL層面,去執行一個邏輯程式碼
if
where , set , choose ,when
Foreach
遍歷集合等
select * from user where 1=1 and
<foreach item="id" collection="ids"
open="(" separator="or" close=")">
#{id}
</foreach>
(id=1 or id=2 or id=3)
<!--
select * from mybatis.blog where 1=1 and (id=1 or id = 2 or id=3)
我們現在傳遞一個萬能的map , 這map中可以存在一個集合!
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
動態SQL就是在拼接SQL語句,我們只要保證SQL的正確性,按照SQL的格式,去排列組合就可以了
SQL片段
功能的部分抽取出來,方便複用
-
使用SQL標籤抽取公共的部分
<sql id="if-title-author"> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </sql>
-
在需要使用的地方使用Include標籤引用即可
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <include refid="if-title-author"></include> </where> </select>
注意事項:
- 最好基於單表來定義SQL片段!
- 不要存在where標籤
快取
簡介
快取 [ Cache ]
存在記憶體中的臨時資料,將使用者經常查詢的資料放在快取(記憶體)中,使用者去查詢資料就不用從磁碟上(關係型資料庫資料檔案)查詢,從快取中查詢,從而提高查詢效率,解決高併發系統的效能問題。以減少和資料庫的互動次數,減少系統開銷,提高系統效率。
Mybatis快取
系統定義兩級快取:一級快取和二級快取
-
預設情況下,只有一級快取開啟。(SqlSession級別的快取,也稱為本地快取)
-
二級快取需要手動開啟和配置,他是基於namespace級別的快取。
-
為了提高擴充套件性,MyBatis定義了快取介面Cache。我們可以通過實現Cache介面來自定義二級快取
一級快取
又名本地快取: SqlSession
與資料庫同一次會話期間查詢到的資料會放在本地快取中, 以後如果需要獲取相同的資料,直接從快取中拿,沒必須再去查詢資料庫;
測試步驟:
- 開啟日誌!
- 測試在一個Sesion中查詢兩次相同記錄
- 檢視日誌輸出
快取失效的情況:
-
查詢不同的東西
-
增刪改操作,可能會改變原來的資料,所以必定會重新整理快取!
3.手動清除快取
sqlSession.clearCache()
小結:一級快取預設是開啟的,只在一次SqlSession中有效,也就是拿到連線到關閉連線這個區間段!一級快取就是一個Map。
二級快取
- 二級快取也叫全域性快取,一級快取作用域太低了,所以誕生了二級快取
- 基於namespace級別的快取,一個名稱空間,對應一個二級快取;
- 工作機制
- 一個會話查詢一條資料,這個資料就會被放在當前會話的一級快取中;
- 如果當前會話關閉了,這個會話對應的一級快取就沒了;但是我們想要的是,會話關閉了,一級快取中的資料被儲存到二級快取中;
- 新的會話查詢資訊,就可以從二級快取中獲取內容;
- 不同的mapper查出的資料會放在自己對應的快取(map)中;
步驟:
-
開啟全域性快取
<!--顯示的開啟全域性快取--> <setting name="cacheEnabled" value="true"/>
-
在要使用二級快取的Mapper中開啟
<!--在當前Mapper.xml中使用二級快取--> <cache/>
也可以自定義引數
<!--在當前Mapper.xml中使用二級快取--> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
-
測試
-
問題:我們需要將實體類序列化!否則就會報錯!
Caused by: java.io.NotSerializableException: com.kuang.pojo.User
-
小結:
- 只要開啟了二級快取,在同一個Mapper下就有效
- 所有的資料都會先放在一級快取中;
- 只有當會話提交,或者關閉的時候,才會提交到二級緩衝中!
快取原理
Redis資料庫來做快取 K-V
常見異常及錯誤
①關於無法new java類錯誤
現象:只有file
,沒有java class
如下圖
解法:因為該不在可編譯的目錄下,可在 Project Structure 中進行設定
②關於Test測試
(1)下圖情況
方法錯誤(即寫的不是方法 eg: 少了方法的括號)
(2)沒有匯入包 import org.junit.Test;
③關於資料庫查詢xml檔案提示
(1)波浪線為正常
(2)裡面包含的有些SQL語句是不加 ;
④Mapper介面中未建立方法
下圖為在測試程式碼中
解法如下圖:
⑤resultType 與resultMap
Caused by: org.apache.ibatis.type.TypeException: Could not resolve type alias 'Student'. Cause: java.lang.ClassNotFoundException: Cannot find class: Student
原因:將resultMap寫成了resultType,Type對應的是物件類,所以丟擲ClassNotFoundException的異常,mybatis的結果是存放在resultMap中的。
⑥類找不到異常(*)
Could not resolve type alias 'Student'. Cause: java.lang.ClassNotFoundException: Cannot find class: Student
原因分析:找不到類替代的別名,在mybatis-config.xml
,漏寫typeAliases
解決:
基於實戰中學習,學習快樂中成長
.
時間會回答成長,成長會回答夢想