1. MyBatis 的快取機制
@
- 1. MyBatis 的快取機制
- 2. 準備工作
- 3. MyBatis 的一級快取
- 3.1 一級快取失效情況/條件
- 4. MyBatis 的二級快取
- 5. MyBatis 整合 EhCache 第三方快取
- 6. 總結:
- 7. 最後:
快取(Cache)
快取的作用:透過減少 IO 的方式,來提高程式的執行效率 。
MyBatis 的快取:將 Select 語句的查詢結果放到快取(記憶體)當中,下一次還是這條 Select 語句的話,直接就從快取當中取了,不再查詢資料庫。這樣一方面減少了 IO,另一方面不再執行繁瑣的查詢演算法。效率大大提升。
MyBatis 快取包括:
- 一級快取:將查詢到的資料儲存到 SqlSession 中
- 二級快取:將查詢到的資料儲存到 SqlSessionFactory 中
- 或者是整合其它第三方的快取:比如 EhCache(Java語言開發的),Memcache(C語言開發的)等。
注意:快取只針對於 DQL(查詢)語句,也就是說快取機制只對應 Select 語句。
一旦你執行了,insert 或者delete或者 update 更新語句,無論是否是更新修改刪除那個資料表中的記錄,都會清空快取,所以,這樣就不會導致 快取當中的 select 語句的資料是:舊的無用的資料了。
2. 準備工作
資料表結構的設計,資料表名為:t_car
t_car 表中的資料資訊:
在pom.xml
檔案當中配置相關的依賴的 jar 包如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rainbowsea</groupId>
<artifactId>mybatis-005-crud-blog</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- mybatis 的依賴-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- 引入 logback的依賴,這個日誌框架實現了slf4j 規範-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
</project>
配置 logback 的配置檔案,用於列印顯示,我們的日誌資訊,方便我們檢視我們的執行過程,效果。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- 控制檯輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化輸出:%d表示日期,%thread表示執行緒名,%-5level:級別從左顯示5個字元寬度%msg:日誌訊息,%n是換行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--mybatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日誌輸出級別,logback日誌級別包括五個:TRACE < DEBUG < INFO < WARN < ERROR -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
配置 MyBatis 的核心配置檔案,
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 使用 <package> 還可以將這個包下的所有的類的全部自動起別名,別名就是簡名,不區分大小寫 -->
<package name="com.rainbowsea.mybatis.pojo"/>
</typeAliases>
<environments default="mybatis">
<environment id="mybatis">
<!-- MANAGED 沒有用第三框架管理的話,都是會被提交的,沒有事務上的管理了 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="MySQL123"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 這裡也是可以使用 package 包名掃描,但是同樣的:對應介面路徑要一致,介面名一致-->
<package name="com.rainbowsea.mybatis.mapper"></package>
</mappers>
</configuration>
對照 t_car 建立的ORM 對映的 Car 類
注意:在MyBatis 當中對應的ORM ,一般在框架裡對應的 Bean實體類,一定要實現該 set 和 get 方法以及無引數構造方法,無法框架無法使用反射機制,進行操作 。
建議用包裝類,這樣可以防止 Null的問題,因為(簡單型別 int num = null ,是不可以賦值為 null)的編譯無法透過
package com.rainbowsea.mybatis.pojo;
public class Car {
// 資料庫表當中的欄位應該和pojo類的屬性一一對應
// 建議使用包裝類,這樣可以防止null的問題
private Long id;
private String carNum;
private String brand;
private Double guidePrice;
private String produceTime;
private String carType;
public Car() {
}
public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
this.id = id;
this.carNum = carNum;
this.brand = brand;
this.guidePrice = guidePrice;
this.produceTime = produceTime;
this.carType = carType;
}
@Override
public String toString() {
return "Car{" +
"id=" + id +
", carNum='" + carNum + '\'' +
", brand='" + brand + '\'' +
", guidePrice=" + guidePrice +
", produceTime='" + produceTime + '\'' +
", catType='" + carType + '\'' +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCarNum() {
return carNum;
}
public void setCarNum(String carNum) {
this.carNum = carNum;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Double getGuidePrice() {
return guidePrice;
}
public void setGuidePrice(Double guidePrice) {
this.guidePrice = guidePrice;
}
public String getProduceTime() {
return produceTime;
}
public void setProduceTime(String produceTime) {
this.produceTime = produceTime;
}
public String getcarType() {
return carType;
}
public void setcarType(String catType) {
this.carType = catType;
}
}
3. MyBatis 的一級快取
一級快取預設是開啟的。不需要做任何配置。
原理:只要使用同一個SqlSession物件執行同一條SQL語句,就會走快取。
一級快取的內容是:將查詢到的資料儲存到 SqlSession 當中的。注意:其快取的作用域
package com.rainbowsea.mybatis.mapper;
import com.rainbowsea.mybatis.pojo.Car;
import com.rainbowsea.mybatis.pojo.Clazz;
public interface CarMapper {
Car selectById(Long id);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 一定要是:對應的介面的全限定類名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
<!-- id 要是 namespace 對應介面上的方法名: -->
<select id="selectById" resultType="Car">
select id, car_num, brand, guide_price, produce_time, car_type
from t_car
where id = #{id}
</select>
</mapper>
執行測試:
@Test
public void testSelectById() throws IOException {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
SqlSession sqlSession = sqlSessionFactory.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectById(118L);
System.out.println(car);
CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(118L);
System.out.println(car1);
}
執行 Select 查詢語句的時候,首先從對應的這個 Select 語句的 SqlSession 物件(一級快取)當中查詢是否有對應該Select 查詢語句的快取有的話,就不執行該 查詢的 SQL 語句了,而是直接從一級快取當中取出這個 Select 查詢語句的資料結果。第一次執行 Select 語句(因為MyBatis 一級快取預設是開啟的)就會將存入到 sqlSession 物件(一級快取)當中,方便後續的查詢。
3.1 一級快取失效情況/條件
一級快取失效了,二級快取同樣也是失效的了,所以一級快取失效的條件也是二級快取失效的條件,他們的條件都是一樣的。
思考:什麼時候不走快取?
- sqlSession 物件不是同一個,肯定不走快取。
- 查詢條件不一樣,肯定不走快取。
一級快取失效情況包括兩種:
- 第一種:第一次查詢和第二次查詢之間,手動清空了一級快取。執行:執行了 sqlSession.clearCache()方法,這是手動情況快取。
- 第二種:執行了INSERT 或 DELETE 或UPDATE語句,不管你是操作任意一張表,都會清空一級快取。
無論你是,你做了以上兩件事的任意一種,都會讓一級快取清空 。
第一種:第一次查詢和第二次查詢之間,手動清空了一級快取。執行:執行了 sqlSession.clearCache()方法,這是手動情況快取。
測試:
package com.rainbowsea.mybatis.test;
import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import com.rainbowsea.mybatis.pojo.Clazz;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
public class CarMapperTest {
/**
* 思考:什麼時候不走快取?
* sqlsession 物件不是同一個,肯定不走快取
* 查詢條件不一樣,肯定不走快取
* <p>
* 思考什麼時候一級快取失敗?
* 第一次DQL和第二次DQL之間你做了一下兩件事的任意一種,都會讓一級快取清空
* 1. 執行了 sqlSession.clearCache()方法,這是手動情況快取
* 2. 執行了INSERT 或 DELETE 或UPDATE語句,不管你是操作那張表,都會清空一級快取
*
* @throws IOException
*/
@Test
public void testSelectById3() throws IOException {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
SqlSession sqlSession = sqlSessionFactory.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectById(118L);
System.out.println(car);
// 手動清空一級快取
sqlSession.clearCache();
CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(118L);
System.out.println(car1);
sqlSession.close();
}
}
- 第二種:第一次查詢和第二次查詢之間,執行了增刪改操作。【這個增刪改和哪張表沒有關係,只要有insert delete update操作,一級快取就失效。】
@Test
public void testSelectById3() throws IOException {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
SqlSession sqlSession = sqlSessionFactory.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectById(118L);
System.out.println(car);
// 在這裡執行 insert或者 delete 或者 update 中的任意一個語句,並且和表沒有關係
CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);
mapper2.insertClazz(new Clazz(2000,"高三三班"));
CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(118L);
System.out.println(car1);
sqlSession.close();
}
4. MyBatis 的二級快取
二級快取的範圍是SqlSessionFactory。
二級快取:將查詢到的資料儲存到 SqlSessionFactory 中,範圍比一級快取中更大一些。
使用二級快取步驟/條件 :
- 要在 MyBatis 的核心配置檔案當中,設定<setting name="cacheEnabled" value="true"> 全域性性地開啟或關閉所有對映器配置檔案中已配置的任何快取。預設就是true,無需設定 。
- 在需要使用二級快取的 對應的
SqlMapper.xml
檔案中新增配置:- 使用二級快取的實體類物件必須是可序列化的,也就是對應的POJO實體類,必須實現java.io.Serializable 介面
- 只有 當 SqlSession物件關閉或提交之後,一級快取中的資料才會被寫入到二級快取當中。此時二級快取才可用,不然沒有提交/關閉,二級快取是沒有儲存到資料資訊的,是無效的。
第一步: 要在 MyBatis 的核心配置檔案當中,設定<setting name="cacheEnabled" value="true"> 全域性性地開啟或關閉所有對映器配置檔案中已配置的任何快取。預設就是true,無需設定 。
第二步: 在需要使用二級快取的 對應的 SqlMapper.xml
檔案中新增配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 一定要是:對應的介面的全限定類名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
<!--
預設情況下,二級快取機制是開啟的
只需要在對應的SqlMapper.xml檔案中新增以下標籤,用來表示“我”使用該二級快取
-->
<cache></cache>
<insert id="insertClazz">
insert into t_clazz values (#{cid},#{cname})
</insert>
</mapper>
第三步: 使用二級快取的實體類物件必須是可序列化的,也就是對應的POJO實體類,必須實現java.io.Serializable 介面
第四步: 只有 當 SqlSession物件關閉或提交之後,一級快取中的資料才會被寫入到二級快取當中。此時二級快取才可用,不然沒有提交/關閉,二級快取是沒有儲存到資料資訊的,是無效的。
import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import com.rainbowsea.mybatis.pojo.Clazz;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
public class CarMapperTest {
@Test
public void testSelectById4() throws IOException {
// 這裡只有一個SqlSessionFactory 物件,二級快取對應的就是SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
// 這行程式碼執行結束之後,時間上資料快取到一級快取當中了,(sqlSession是一級快取)
Car car = mapper1.selectById(118L);
System.out.println(car);
// 如果這裡不關閉sqlSession物件的話,二級快取中還是沒有資料的
// 如果執行了這行程式碼,sqlSession1的一級快取中的資料會放到二級快取當中
sqlSession1.close();
// 這行程式碼執行結束之後,實際上資料會快取到一級快取當中。(sqlSession2 是一級快取)
Car car1 = mapper2.selectById(118L);
System.out.println(car1);
// 程式執行到這裡的時候,會有SqlSession1這個一級快取中的資料寫入到二級快取當中
// sqlSession1.close()
// 程式執行到這裡的時候,會將sqlSession2這個一級快取中的資料寫入到二級快取當中
sqlSession2.close();
}
}
執行測試:
二級快取的失效:只要兩次查詢之間出現了增刪改操作。二級快取就會失效。【一級快取也會失效】
二級快取的相關配置:
-
eviction :指定從快取中移除某個物件的淘汰演算法。預設採用LRU策略。
-
- LRU:Least Recently Used。最近最少使用。優先淘汰在間隔時間內使用頻率最低的物件。(其實還有一種淘汰演算法LFU,最不常用。)
- FIFO:First In First Out。一種先進先出的資料快取器。先進入二級快取的物件最先被淘汰。
- SOFT:軟引用。淘汰軟引用指向的物件。具體演算法和JVM的垃圾回收演算法有關。
- WEAK:弱引用。淘汰弱引用指向的物件。具體演算法和JVM的垃圾回收演算法有關。
-
flushInterval :
-
- 二級快取的重新整理時間間隔。單位毫秒。如果沒有設定。就代表不重新整理快取,只要記憶體足夠大,一直會向二級快取中快取資料。除非執行了增刪改。
-
readOnly :
-
- true:多條相同的sql語句執行之後返回的物件是共享的同一個。效能好。但是多執行緒併發可能會存在安全問題。
- false:多條相同的sql語句執行之後返回的物件是副本,呼叫了clone方法。效能一般。但安全。
-
size :
-
- 設定二級快取中最多可儲存的java物件數量。預設值1024。
5. MyBatis 整合 EhCache 第三方快取
整合EhCache是為了代替mybatis自帶的二級快取。一級快取是無法替代的。
mybatis對外提供了介面,也可以整合第三方的快取元件。比如EhCache、Memcache等。都可以。
EhCache是Java寫的。Memcache是C語言寫的。所以mybatis整合EhCache較為常見,按照以下步驟操作,就可以完成整合:
第一步: 引入mybatis 整合 ehcache 的依賴。
<!--mybatis整合ehcache的元件-->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
第二步: 在類的根路徑下新建 echcache.xml
(檔名必須是:echcache.xml 不可以修改)檔案,並提供以下配置資訊。
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<!--磁碟儲存:將快取中暫時不使用的物件,轉移到硬碟,類似於Windows系統的虛擬記憶體-->
<diskStore path="e:/ehcache"/>
<!--defaultCache:預設的管理策略-->
<!--eternal:設定快取的elements是否永遠不過期。如果為true,則快取的資料始終有效,如果為false那麼還要根據timeToIdleSeconds,timeToLiveSeconds判斷-->
<!--maxElementsInMemory:在記憶體中快取的element的最大數目-->
<!--overflowToDisk:如果記憶體中資料超過記憶體限制,是否要快取到磁碟上-->
<!--diskPersistent:是否在磁碟上持久化。指重啟jvm後,資料是否有效。預設為false-->
<!--timeToIdleSeconds:物件空閒時間(單位:秒),指物件在多長時間沒有被訪問就會失效。只對eternal為false的有效。預設值0,表示一直可以訪問-->
<!--timeToLiveSeconds:物件存活時間(單位:秒),指物件從建立到失效所需要的時間。只對eternal為false的有效。預設值0,表示一直可以訪問-->
<!--memoryStoreEvictionPolicy:快取的3 種清空策略-->
<!--FIFO:first in first out (先進先出)-->
<!--LFU:Less Frequently Used (最少使用).意思是一直以來最少被使用的。快取的元素有一個hit 屬性,hit 值最小的將會被清出快取-->
<!--LRU:Least Recently Used(最近最少使用). (ehcache 預設值).快取的元素有一個時間戳,當快取容量滿了,而又需要騰出地方來快取新的元素的時候,那麼現有快取元素中時間戳離當前時間最遠的元素將被清出快取-->
<defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
</ehcache>
第三步: 修改對應的 SqlMapper.xml檔案中的
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 一定要是:對應的介面的全限定類名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
<!--
預設情況下,二級快取機制是開啟的
只需要在對應的SqlMapper.xml檔案中新增以下標籤,用來表示“我”使用該二級快取
-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
<!-- id 要是 namespace 對應介面上的方法名: -->
<select id="selectById" resultType="Car">
select id, car_num, brand, guide_price, produce_time, car_type
from t_car
where id = #{id}
</select>
</mapper>
第四步:編寫測試程式使用。
import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import com.rainbowsea.mybatis.pojo.Clazz;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
public class CarMapperTest {
@Test
public void testSelectById5() throws Exception {
// 這裡只有一個SqlSessionFactory 物件,二級快取對應的就是SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
SqlSession sqlSession1 = sqlSessionFactory.openSession();
CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(118L);
System.out.println(car1);
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
Car car2 = mapper2.selectById(118L);
System.out.println(car2);
sqlSession2.close();
}
}
6. 總結:
- MyBatis 快取包括:
- 一級快取:將查詢到的資料儲存到 SqlSession 中
- 二級快取:將查詢到的資料儲存到 SqlSessionFactory 中
- 或者是整合其它第三方的快取:比如 EhCache(Java語言開發的),Memcache(C語言開發的)等。
- 注意:快取只針對於 DQL(查詢)語句,也就是說快取機制只對應 Select 語句。
- 一級快取預設是開啟的
- 一級快取失效情況包括兩種:
- 第一種:第一次查詢和第二次查詢之間,手動清空了一級快取。執行:執行了 sqlSession.clearCache()方法,這是手動情況快取。
- 第二種:執行了INSERT 或 DELETE 或UPDATE語句,不管你是操作任意一張表,都會清空一級快取。
- 一級快取失效了,二級快取也是失效了,二級快取是透過將一級快取的快取儲存到二級快取當中的,所以一級失效,二級也是失效的
- 二級快取:將查詢到的資料儲存到 SqlSessionFactory 中,範圍比一級快取中更大一些。
7. 最後:
“在這個最後的篇章中,我要表達我對每一位讀者的感激之情。你們的關注和回覆是我創作的動力源泉,我從你們身上吸取了無盡的靈感與勇氣。我會將你們的鼓勵留在心底,繼續在其他的領域奮鬥。感謝你們,我們總會在某個時刻再次相遇。”