javascript
SpringBoot整合Mybatis(高级)
SpringBoot整合Mybatis(高級)
文章目錄
- SpringBoot整合Mybatis(高級)
- 前言
- 基礎環(huán)境配置
- 增刪改查
- ResultMap
- 復雜查詢
- 多對一
- 一對多
- 動態(tài)SQL
- if
- choose
- trim
- SQL片段
- foreach
- 緩存
- 一級緩存
- 二級緩存
- 參考文章
前言
花了三天時間,看完了B站上的 IDEA 版 Mybatis 的視頻教程,確實從 UP 主那里學到了很多東西。UP 講課很有激情,而且以練促學這種方式很容易學到東西,真的要給 UP 點個大大的贊。
UP 是用 Maven 導入項目然后進行 Mybatis 的教學,這里我采用的是 SpringBoot 來集成 Mybatis,根據節(jié)奏一步步學習完了 Mybatis 的知識。
應該來說本質上的東西,像 SQL 之類都是一樣的,但是配置方面因為環(huán)境不同,所以也不太一樣。
這篇博客用來記錄 SpringBoot 集成 Mybatis 的一整個學習過程,算是對自己學習的一個總結。
這里我用的是 IDEA 進行的 SpringBoot 項目的搭建,然后整合了 Mybatis在項目中。
- 搭建 SpringBoot+Mybatis 項目的流程請參考這篇文章 SpringBoot整合Mybatis超詳細流程,
- 同時,我們在實踐中使用了 Lombok 插件,也請參考這篇文章進行 Lombok 的配置 Lombok插件的安裝與使用。
基礎環(huán)境配置
users數據表設計如下
在 application.yml 中進行配置
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true & characterEncoding=utf-8 &useSSL=false & serverTimezone=Asia/Shanghaiusername: rootpassword: 123456mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.example.entitylogging:level:com:example:dao:debug在 mybatis 配置中,mapper-locations指定了 xml 文件的地址, type-aliases-package: com.example.entity,這樣在 xml 中parameterType、resultType都能使用簡寫
如果我們要打印 mybatis 的日志,配置對應mapper所在包的日志級別即可。這里可以看到,“l(fā)ogging.level”是前綴,“com.example.dao”是Dao層接口所在的包路徑。
這里我們沒有用到 controller 和 service,目錄結構我們只需要 entity、dao和mapper。我們定義好實體類和 dao 層接口、編寫 mapper.xml 之后,用 JUnit 測試類進行查看。
增刪改查
Entity層
package com.example.entity;import lombok.AllArgsConstructor; import lombok.Data;@Data @AllArgsConstructor public class User {private int id;private String name;private String pwd; }Dao層
@Repository public interface UserDao {//查詢所有用戶List<User> getAll();//根據id查用戶User getUserById(int id);//刪除用戶void deleteUser(int id);//更新用戶信息void updateUser(User user);//增加用戶void insertUser(User user); }增刪改查 insert、delete、update、select
<mapper namespace="com.example.dao.UserDao"><!--查--><select id="getAll" resultType="User">select * from `users` ;</select><select id="getUserById" parameterType="int" resultType="User">select * from `users` where id=#{id};</select><!--增--><insert id="insertUser" parameterType="User">insert into `users` (id, name, pwd) values (#{id}, #{name}, #{pwd});</insert><!--改--><update id="updateUser" parameterType="User">update `users` set name=#{name},pwd=#{pwd} where id=#{id};</update><!--刪--><delete id="deleteUser" parameterType="int">delete from `users` where id=#{id};</delete></mapper>測試類
@Autowired private UserDao userDao;@Test void contextLoads() {userDao.insertUser(new User(4, "haha", "123"));userDao.updateUser(new User(3, "jackYYY", "zzz"));//userDao.deleteUser(4);User user = userDao.getUserById(3);System.out.println(user);List<User> list = userDao.getAll();System.out.println(list);}- 如果我們在 dao 中用 @Param 指定參數名稱,則在 xml 中不需要指定 parameterType,sql 中使用指定名稱
- 或者我們在 dao 中使用 hashMap 類型傳值, parameterType=map,sql中使用 map 指定的 key (多參數傳遞時推薦用 map )
一個經驗:如果在任何一個 xml 里面寫了任何的增刪改查,一定要在 Dao 層接口中有對應的方法,否則項目運行一定報錯。
ResultMap
結果集映射,用于解決數據庫字段與 Java實體類的屬性不一致的情況
id name pwd -> id name password如果我們的Entity層定義為:
import lombok.Data;@Data public class User2 {private int id;private String name;private String password; }這樣的話數據庫字段和實體類屬性不一致,查詢出來的 password 一列為空,對于這種情況我們可以使用 resultMap 進行解決。
<resultMap id="UserMap" type="User2"><!--column數據庫中的字段,property實體類中的屬性--><result column="id" property="id"></result><result column="name" property="name"></result><result column="pwd" property="password"></result> </resultMap><select id="getAll" resultMap="UserMap">select * from `users`; </select>復雜查詢
resultMap 元素是 MyBatis 中最重要最強大的元素。ResultMap 的設計思想是,對簡單的語句做到零配置,對于復雜一點的語句,只需要描述語句之間的關系就行了。
比如現在有兩個表,一個學生表、一個老師表,多個學生對一個老師是關聯(lián)【多對一】,一個老師有很多學生是集合【一對多】
我們先在 MySQL 數據庫中建表,老師表有兩個字段,id、name。學生表有三個字段,id、name、tid,其中 tid 是外鍵,對應老師的 id
CREATE TABLE teacher(id int(10) not null,name varchar(20) DEFAULT null,PRIMARY KEY(id) )INSERT INTO teacher(id, name) VALUES(1, '秦老師');CREATE TABLE student(id int(10) not null,name VARCHAR(20) DEFAULT NULL,tid int(10) DEFAULT NULL,PRIMARY KEY(id),FOREIGN KEY(tid) REFERENCES teacher(id) )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);多對一
我們使用 Lombok 建立老師、學生類
@Data public class Teacher {private int id;private String name; }@Data public class Student {private int id;private String name;//學生關聯(lián)一個老師private Teacher teacher; }在 resultMap 中,查詢對象使用 association,集合使用 collection。
JavaType:指定實體類中屬性的類型
association 中的 select 即嵌套查詢
方法一:按照查詢嵌套處理
我們要查詢外鍵中 teacher 的 tid,需要嵌套查詢。建立學生實體類下的老師對象,即意味著適用 association
Dao層
@Repository public interface StudentDao {//查詢所有學生信息,以及對應的老師信息List<Student> getStudent();List<Student> getStudent2(); }Mapper
<select id="getStudent" resultMap="StudentMap">select * from `student`; </select><resultMap id="StudentMap" type="Student"><!--property是實體類屬性,column是數據庫的列--><result property="id" column="id"/><result property="name" column="name"/><association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/> </resultMap><select id="getTeacher" resultType="Teacher">select * from `teacher` where id=#{tid}; </select>測試類
@Autowired private StudentDao studentDao;@Test public void getStudent(){List<Student> list2 = studentDao.getStudent();for (Student x: list2){System.out.println(x);} }方法二:按照結果嵌套處理
直接根據實體類的屬性進行結果查詢,其中需要的對象直接用 association 構造查詢
<select id="getStudent2" resultMap="StudentMap2">select s.id sid, s.name sname,t.name tnamefrom `student` s, `teacher` twhere s.tid = t.id; </select><resultMap id="StudentMap2" type="Student"><result property="id" column="sid"/><result property="name" column="sname"/><association property="teacher" javaType="Teacher"><result property="name" column="tname"/></association> </resultMap>結果為:
一對多
我們同樣使用剛才在數據庫中建立的老師表和學生表
使用 Lombok 建立學生、老師類
@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; }建立老師實體類下的List< Student >泛型,即意味著在 resultMap 中適用 collection
ofType:指定的這個 List 所存放的 JavaBean 的類型
方法一:按照結果嵌套處理
Dao層
@Repository public interface TeacherDao {//獲取指定老師下的所有學生及老師的信息Teacher getTeacher(@Param("tid") int id);Teacher getTeacher2(@Param("tid") int id); }Mapper
<select id="getTeacher" resultMap="TeacherMap">select s.id sid, s.name sname, t.name tname, t.id tidfrom `student` s, `teacher` twhere s.tid = t.id and t.id=#{tid} </select><resultMap id="TeacherMap" type="Teacher"><result property="id" column="tid"/><result property="name" column="tname"/><!--javaType="ArrayList"在這里可有可無--><collection property="students" ofType="Student"><result property="id" column="sid"/><result property="name" column="sname"/><result property="tid" column="tid"/></collection> </resultMap>測試類
@Autowired private TeacherDao teacherDao;@Test public void getTeacher(){Teacher teacher = teacherDao.getTeacher(1);System.out.println(teacher); }結果為:
方法二:使用查詢嵌套處理
<select id="getTeacher2" resultMap="TeacherMap2">select * from `teacher` where id=#{tid}; </select><resultMap id="TeacherMap2" type="Teacher"><collection property="students" javaType="ArrayList" ofType="Student"select="getStudent" column="id"/> </resultMap><select id="getStudent" resultType="Student">select * from `student` where tid=#{tid}; </select>動態(tài)SQL
動態(tài)SQL:指根據不同的條件生成不同的SQL語句,擺脫拼接SQL的痛苦
我們在數據庫中建立一個博客表,字段有 id、title、author、create_time、views
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 '創(chuàng)建時間',views int(30) not null COMMENT '瀏覽量' )建立實體類
@Data public class Blog {private String id;private String title;private String author;private Date createTime;private int views; }博客ID并不是使用數字自增,而是使用隨機數來保證ID唯一,所以我們需要一個工具類來生成唯一ID
新建 utils 包,包下新建 IDutils 類
//因為隨機生成的UUID中含有'-'字符,所以我們把字符去掉 public class IDutils {public static String getID(){return UUID.randomUUID().toString().replaceAll("-", "");} }我們可以去測試類進行查看
@Test public void testID(){System.out.println(IDutils.getID()); }然后我們插入數據
Dao層
@Repository public interface BlogDao {//插入數據int addBlog(Blog blog);//IF查詢博客List<Blog> queryBlogIF(Map map);//Choose查詢博客List<Blog> queryBlogChoose(Map map);//Set更新博客int updateBlog(Map map); }Mapper
<insert id="addBlog" parameterType="Blog">insert into `blog` (id, title, author, create_time, views)values (#{id}, #{title}, #{author}, #{createTime}, #{views}) </insert>測試類
@Test public void addBlog(){Blog blog = new Blog();blog.setId(IDutils.getID());blog.setTitle("Mybatis很好玩");blog.setAuthor("Kiros");blog.setCreateTime(new Date());blog.setViews(9999);blogDao.addBlog(blog);blog.setId(IDutils.getID());blog.setTitle("Java很好玩");blogDao.addBlog(blog);blog.setId(IDutils.getID());blog.setTitle("Spring很好玩");blogDao.addBlog(blog);blog.setId(IDutils.getID());blog.setTitle("微服務很好玩");blogDao.addBlog(blog); }結果:
if
使用動態(tài) SQL 最常見情景是根據條件包含 where 子句的一部分。
如果我們不傳入參數 title,那么所有的 Blog 都會返回;如果傳入了 “title” 參數,那么就會對 “title” 進行查找并返回對應的 BLOG 結果,對于 “author” 參數同理。
<select id="queryBlogIF" parameterType="map" resultType="Blog">select * from `blog` where 1=1<if test="title != null">and title=#{title}</if><if test="author != null">and author=#{author}</if> </select>在測試類中傳入數據進行測試
@Test public void queryBlogIF(){//不傳入參數HashMap map = new HashMap();/*傳入title和authormap.put("title", "Mybatis很好玩");map.put("authpr", "Kiros");*/List<Blog> blogs = blogDao.queryBlogIF(map);for(Blog blog: blogs){System.out.println(blog);} }不傳入參數時查詢出四條記錄,傳入參數后查詢出一條記錄
choose
有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用。針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。
Choose標簽下結合 when、otherwies 標簽來使用,只要滿足第一個when,就不再往下查找。這個特性和 switch——case——default 是一致的。
傳入了 “title” 就按 “title” 查找,傳入了 “author” 就按 “author” 查找的情形。若兩者都沒有傳入,就返回 views 為 9999 的 BLOG
<select id="queryBlogChoose" parameterType="map" resultType="Blog">select * from `blog` where <choose><when test="title != null">title=#{title}</when><when test="author != null">and author=#{author}</when><otherwise>and views=9999</otherwise></choose> </select>但是以上SQL代碼有個問題,如果 title 為空,而 author 不為空,SQL就會被拼接為 select * from blog where and author=#{author} ,這個查詢明顯會失敗。為了解決這個問題,mybatis 中引入了 where 元素。
where 元素只會在子元素返回任何內容的情況下才插入 “WHERE” 子句。而且,若子句的開頭為 “AND” 或 “OR”,where 元素也會將它們去除。這樣就避免了SQL拼接時出現的問題。
<select id="queryBlogChoose" parameterType="map" resultType="Blog">select * from `blog`<where><choose><when test="title != null">title=#{title}</when><when test="author != null">and author=#{author}</when><otherwise>and views=9999</otherwise></choose></where> </select>在測試類中傳入數據進行測試
@Test public void queryBlogChoose(){//不傳入參數HashMap map = new HashMap();//傳入title和author//map.put("title", "Mybatis很好玩");map.put("authpr", "Kiros");List<Blog> blogs = blogDao.queryBlogChoose(map);for(Blog blog: blogs){System.out.println(blog);} }trim
用于動態(tài)更新語句的類似解決方案叫做 set。set 元素可以用于動態(tài)包含需要更新的列,忽略其它不更新的列。
同時,set 元素會動態(tài)地在行首插入 SET 關鍵字,并會刪掉額外的逗號(這些逗號是在使用條件語句給列賦值時引入的)。
<update id="updateBlog" parameterType="map">update `blog`<set><if test="title != null">title=#{title},</if><if test="author != null">author=#{author}</if></set>where id=#{id} </update>在測試類中傳入數據進行測試
@Test public void updateBlog(){HashMap map = new HashMap();//傳入title和authormap.put("title", "Mybatis很好玩aaaaaaa");//map.put("authpr", "Kiros");map.put("id", "ad0b3e7f08924eca98db184fbe4e8d9b");blogDao.queryBlogChoose(map);System.out.println("更新成功"); }如果 where 元素與你期望的不太一樣,你也可以通過自定義 trim 元素來定制 where 元素的功能。比如,和 where 元素等價的自定義 trim 元素為:
<trim prefix="WHERE" prefixOverrides="AND |OR ">... </trim>prefixOverrides 屬性會忽略通過管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子會移除所有 prefixOverrides 屬性中指定的內容,并且插入 prefix 屬性中指定的內容。
同理,我們也可以自定義 trim 來定制 set 元素,與 set 元素等價的自定義 trim 元素為:
<trim prefix="SET" suffixOverrides=",">... </trim>一般來說,默認的 where、set就可以解決我們大部分的問題,如果需要,再進行定制化開發(fā)。
SQL片段
有時候我們需要把一些公共的 SQL 片段抽取出來,方便復用
我們使用 sql 標簽抽取公共部分,然后在需要的地方使用 include 標簽引用
<sql id="if-title-author"><if test="title != null">and title=#{title}</if><if test="author != null">and author=#{author}</if> </sql><select id="queryBlogIF" parameterType="map" resultType="Blog">select * from `blog`<where><include refid="if-title-author"></include></where> </select><!--等價寫法--> <select id="queryBlogIF" parameterType="map" resultType="Blog">select * from `blog`<where><if test="title != null">and title=#{title}</if><if test="author != null">and author=#{author}</if></where> </select>注意,盡量基于單表來定義SQL片段,sql 標簽內最好不要包含 where 標簽。
foreach
動態(tài) SQL 的另一個常見使用場景是對集合進行遍歷(尤其是在構建 IN 條件語句的時候)。
foreach 元素的功能非常強大,它允許你指定一個集合,聲明可以在元素體內使用的集合項(item)和索引(index)變量。它也允許你指定開頭與結尾的字符串以及集合項迭代之間的分隔符。這個元素也不會錯誤地添加多余的分隔符。
你可以將任何可迭代對象(如 List、Set 等)、Map 對象或者數組對象作為集合參數傳遞給 foreach。當使用可迭代對象或者數組時,index 是當前迭代的序號,item 的值是本次迭代獲取到的元素。當使用 Map 對象(或者 Map.Entry 對象的集合)時,index 是鍵,item 是值。
我們先去數據庫中把博客的 id 都改為數字,這樣方便我們使用 foreach 進行查詢。
現在我們要使用 foreach 查詢博客 id 為 1、2、3 的博客,sql為:
select * from blog where 1=1 and(id=1 or id=2 or id=3)根據 sql 構建 foreach,我們之后會在測試類中傳入一個集合,集合名字叫做 ids,集合中的元素是 id,指定的開頭是 and(,結尾是),分隔符是 or。
<select id="queryBlogForeach" parameterType="map" resultType="Blog">select * from `blog`<where><foreach collection="ids" item="id" open="and (" close=")" separator="or">id=#{id}</foreach></where> </select>測試類
@Test public void queryBlogForeach(){HashMap map = new HashMap();ArrayList<Integer> ids = new ArrayList<Integer>();ids.add(1);ids.add(2);ids.add(3);map.put("ids", ids);List<Blog> blogs = blogDao.queryBlogForeach(map);for (Blog blog : blogs) {System.out.println(blog);} }建議:先在 MySQL 中寫出完整的 SQL 語句,再對應地去修改成為需要的動態(tài) SQL 即可。
緩存
平時我們查詢數據庫的時候都要損耗資源,因此我們想到可以把一些數據暫時存放在內存的一個地方,這就是緩存。當我們再次查詢相同數據時,可以直接從緩存中取出數據,就不用再從數據庫中查詢了。
緩存是存放在內存中的臨時數據,從緩存中查詢數據可以減少和數據庫的交互次數,降低系統(tǒng)開銷,提高查詢的效率,從而提升高并發(fā)系統(tǒng)的性能。經常查詢并且不經常改變的數據 適合使用緩存,否則不適合使用緩存。
MyBatis 內置了一個強大的事務性查詢緩存機制,它可以非常方便地配置和定制。
Mybatis 系統(tǒng)默認定義了兩級緩存:一級緩存和二級緩存。
- 一級緩存,也稱本地緩存,SqlSession級別,僅僅對一個會話中的數據進行緩存
- 二級緩存,namespace級別的緩存,會對全局的數據進行緩存,
- Mybatis 還定義了緩存接口 cache,我們可以通過緩存接口來自定義二級緩存
SpringBoot中默認一級緩存不需要在配置文件去配置,默認開啟,一級緩存不能被關閉,只能配置緩存范圍:Session或者Statement。二級緩存也是默認開啟的,但是可以通過 application.yml 配置文件關閉或者開啟,同時,如果要使用二級緩存則需要在 xml 文件中配置。
# 關閉/開啟二級緩存 mybatis:configuration:cache-enabled: false/true通常情況下,如果同時設置了一級緩存和二級緩存,會先使用二級緩存的數據,然后再使用一級緩存的數據,最后才會訪問數據庫。
一級緩存
這里我們使用數據庫中的 users 表(一開始建立的那個表)進行查詢,重新建立一個 User 類
@Data public class User {private int id;private String name;private String pwd; }Dao層
@Repository public interface UserDao {//查詢用戶User queryUserById(@Param("id") int id); }Mapper
<select id="queryUserById" resultType="User">select * from `users` where id=#{id}; </select>測試類
@Test public void queryUserById(){User user = userDao.queryUserById(1);System.out.println(user);User user2 = userDao.queryUserById(1);System.out.println(user2); }從日志反饋中可以看出,我們查詢了兩次數據庫,似乎一級緩存沒有生效啊。
這是因為 SpringBoot 集成 Mybatis 時默認每次查詢完之后自動 commite 去提交事務,每次 userDao 調用queryUserById方法都會創(chuàng)建一個 session,并且在執(zhí)行完畢后關閉 session。所以兩次調用并不是同一個 SqlSession,一級緩存永遠不會生效。
想要一級緩存生效的話,我們需要把方法放在一個事務當中,這樣走的就是同一個 SqlSession,一級緩存就又生效了。
@Test @Transactional public void queryUserById(){User user = userDao.queryUserById(1);System.out.println(user);User user2 = userDao.queryUserById(1);System.out.println(user2); }我們可以看到,放在一個事務之中,只查詢了一次數據庫,一級緩存生效。
一級緩存默認是開啟的,只在一次 SqlSession 中有效。相當于一個Map,緩存不失效的情況下每次去 Map 中取數據就行。
緩存失效的情況:
二級緩存
然而,一級緩存的作用域太小,我們一般都會采用二級緩存
工作機制:
- 一個會話查詢一條數據,這個數據就會被放在當前會話的以及緩存中
- 如果當前會話關閉了,這個會話的一級緩存就沒了;但我們想要的是,會話關閉了,一級緩存中的數據被保存到二級緩存中
- 新的會話查詢信息,就可以從二級緩存中獲取內容
- 不同的mapper查出的數據會放在自己對應的緩存中
要啟用全局的二級緩存,只需要在你的 SQL 映射文件(即 xml 文件)中添加一行
<cache/>這個簡單語句的基本效果:
-
映射語句文件中的所有 select 語句的結果將會被緩存。
-
映射語句文件中的所有 insert、update 和 delete 語句會刷新緩存。
-
緩存會使用最近最少使用算法(LRU算法)來清除不需要的緩存。
-
緩存不會定時進行刷新(也就是說,沒有刷新間隔)。
-
緩存會保存列表或對象(無論查詢方法返回哪種)的 1024 個引用。
-
緩存會被視為讀/寫緩存,這意味著獲取到的對象并不是共享的,可以安全地被調用者修改,而不干擾其他調用者或線程所做的潛在修改。
當然,這些屬性可以通過 cache 元素的屬性來修改。比如:
<cacheeviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>這個更高級的配置創(chuàng)建了一個 FIFO 緩存,每隔 60 秒刷新,最多可以存儲結果對象或列表的 512 個引用,而且返回的對象被認為是只讀的,因此對它們進行修改可能會在不同線程中的調用者產生沖突。
參數解讀:
-
eviction(清除策略)屬性指定的是清除緩存的方法,可用的策略有四種
- LRU – 最近最少使用:移除最長時間不被使用的對象。(默認)
- FIFO – 先進先出:按對象進入緩存的順序來移除它們。
- SOFT – 軟引用:基于垃圾回收器狀態(tài)和軟引用規(guī)則移除對象。
- WEAK – 弱引用:更積極地基于垃圾收集器狀態(tài)和弱引用規(guī)則移除對象。
-
flushInterval(刷新間隔)屬性可以被設置為任意的正整數,設置的值應該是一個以毫秒為單位的合理時間量。默認情況是不設置,也就是沒有刷新間隔,緩存僅僅會在調用語句時刷新。
-
size(引用數目)屬性可以被設置為任意正整數,要注意欲緩存對象的大小和運行環(huán)境中可用的內存資源。默認值是 1024。
-
readOnly(只讀)屬性可以被設置為 true 或 false。只讀的緩存會給所有調用者返回緩存對象的相同實例。因此這些對象不能被修改。這就提供了可觀的性能提升。而可讀寫的緩存會(通過序列化)返回緩存對象的拷貝。速度上會慢一些,但是更安全,因此默認值是 false。
二級緩存需要查詢結果映射的 POJO 對象實現 Java.io.Serializable 接口。如果存在父類、成員 POJO 都需要實現序列化接口。否則,執(zhí)行的過程中會直接報錯。
由于二級緩存數據存儲介質多種多樣,不一定在內存有可能是硬盤或者遠程服務器。所以,POJO 類實現序列化接口是為了將緩存數據取出執(zhí)行反序列化操作。
@Data public class User implements Serializable {private int id;private String name;private String pwd; }由于 cache 是針對整個 Mapper 中的查詢方法的,因此當某個 select 方法不需要緩存時,可在對應的 select 標簽中添加 useCache 值為 false 來禁用二級緩存。
<select id="findById" resultType="User" useCache="false">······ </select>下面,我們還是通過剛才一級緩存的實例來操作二級緩存
實體類
@Data public class User implements Serializable {private int id;private String name;private String pwd; }Mapper
<cache/> <select id="queryUserById" resultType="User">select * from `users` where id=#{id}; </select>測試類
@Test public void queryUserById(){User user = userDao.queryUserById(1);System.out.println(user);User user2 = userDao.queryUserById(1);System.out.println(user2); }可以看到,我們只查詢了一次數據庫,第二次是從緩存中取出了數據,命中緩存的概率是 0.5。
小結:
-
只要開啟了二級緩存,在同一個 Mapper 下都有效
-
所有數據都會先放在一級緩存中,當會話提交或者關閉的時候才提交到二級緩存中
-
使用二級緩存一定要記得給 POJO 對象序列化
-
查詢結果實時性要求不高的情況下可采用 Mybatis 二級緩存降低數據庫訪問量,提高訪問速度,同時配合設置緩存刷新間隔 flushInterval 來根據需要改變刷新緩存的頻次。
參考文章
Mybatis3-官方文檔
【狂神說Java】Mybatis最新完整教程IDEA版通俗易懂
Spring Boot集成Mybatis中如何顯示日志
SpringBoot集成Mybatis的一級緩存和二級緩存
Mybatis中的collection標簽中的javaType和ofType屬性的區(qū)別
《新程序員》:云原生和全面數字化實踐50位技術專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的SpringBoot整合Mybatis(高级)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 八、求循环节
- 下一篇: 使用IDEA在SpringBoot项目中