Mybatis的緩存
1、MyBatis 緩存的基本介紹
緩存是一般的 ORM 框架都會提供的功能,目的就是提升查詢的效率和減少數(shù)據(jù)庫的壓力。緩存是存在內(nèi)存中的臨時數(shù)據(jù),將用戶經(jīng)常查詢的數(shù)據(jù)放在緩存(內(nèi)存)中,用戶去查詢數(shù)據(jù)就不用從磁盤上(關(guān)系型數(shù)據(jù)庫文件)查詢,從緩存中查詢,從而提高查詢效率,解決了高并發(fā)系統(tǒng)的性能問題。經(jīng)常查詢并且不經(jīng)常改變的數(shù)據(jù)就可以使用緩存。
MyBatis系統(tǒng)中默認(rèn)定義了兩級緩存:一級緩存和二級緩存
- 默認(rèn)情況下,只有一級緩存開啟(SqlSession級別的緩存,也稱為本地緩存)
- 二級緩存需要手動開啟和配置,他是基于namespace級別的緩存。
- 為了提高可擴展性,MyBatis定義了緩存接口Cache。我們可以通過實現(xiàn)Cache接口來定義二級緩存。
2、一級緩存(本地緩存)
一級緩存也叫本地緩存,一級緩存是默認(rèn)開啟的。
同一個 SqlSession 對象, 在參數(shù)和 SQL 完全一樣的情況下,只執(zhí)行一次 SQL 語句(如果緩存沒有過期)。只有在參數(shù)和 SQL 完全一樣的情況下, 才會有這種情況。
示例:
下面示例需要開啟 mybatis 日志才能看到效果。
假設(shè)我們在一個Session中查詢兩次相同記錄,此時除了第一次查詢外,后面的查詢都會直接使用緩存,而不會再去查詢數(shù)據(jù)庫。
@Test public void test01() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = factory.openSession(); UserDao userDao = session.getMapper(UserDao.class); User user = userDao.findUserById(1); System.out.println("=======分隔符======="); User user2 = userDao.findUserById(1); System.out.println(user == user2); }
日志輸出如下:

可以看到,第一次查詢發(fā)送了 SQL 語句, 后返回了結(jié)果;第二次查詢沒有發(fā)送 SQL 語句, 直接從內(nèi)存中獲取了結(jié)果。兩次查詢獲取到的對象是相同的,這說明第二次查詢是直接從緩存拿到的結(jié)果。
2.1、一級緩存的特性
一級緩存特性:
- 在同一個 SqlSession 中,相同SQL并且參數(shù)相同才會命中緩存。在同一個 SqlSession 中,Mybatis 會把執(zhí)行的 SQL 和參數(shù)通過算法生成緩存的鍵 key, 將鍵 key 和 SQL 查詢的結(jié)果作為 value 值存放在一個 Map 中, 如果后續(xù)的鍵一樣,即 sql 和參數(shù)意義, 則直接從 Map 中獲取緩存數(shù)據(jù)
- 不同的 SqlSession 之間的緩存是相互隔離的。例如查詢一條 SQL 后又重新創(chuàng)建了一個 sqlsession 對象,則這兩個對象之間的緩存是不共用的
- 查詢不同的 mapper 的 xml 配置文件的 sql 語句,緩存不共用
- 任何的增刪改( UPDATE、 INSERT、DELETE)語句都會清空緩存。
- 可以在 mapper 文件的 select 標(biāo)簽中配置 flushCache=“true” ,如 <select id="selectByPrimaryKey" flushCache="true" ...>,這樣每次查詢都會將這個 sqlsession 中的所有緩存清空。或者手動調(diào)用清空緩存的方法 sqlSession.clearCache(); 也可清除緩存。
3、二級緩存(全局緩存)
二級緩存也叫全局緩存,一級緩存作用域太低了,所以誕生了二級緩存。二級緩存存在于 SqlSessionFactory 生命周期中。二級緩存需要手動開啟和配置,它是基于namespace級別的緩存。
緩存機制:會先命中二級緩存,二級緩存中沒有再看一級緩存,都沒有才去查數(shù)據(jù)庫。
3.1、使用二級緩存
在 mybatis 的配置文件 mybatis-config.xml 中添加 <setting name="cacheEnabled" value="true"/> 配置:
<?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> <settings> <!--配置日志--> <setting name="logImpl" value="STDOUT_LOGGING" /> <!--全局地開啟或關(guān)閉配置文件中的所有映射器已經(jīng)配置的任何緩存。 --> <setting name="cacheEnabled" value="true"/> </settings> ... </configuration>
在 mapper 的配置文件 *Mapper.xml 中顯式地開啟二級緩存, 默認(rèn)是不開啟的:
<?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"> <mapper namespace="dao.UserDao"> <!-- 在當(dāng)前Mapper.xml中使用二級緩存。 也可以不配置屬性,直接使用 <cache />。下面配置中的屬性說明如下: 1、緩存的清除策略為 LRU(默認(rèn)值),即最近最少使用:移除最長時間不被使用的對象。 2、每隔 60 秒刷新 3、最多可以存儲結(jié)果對象或列表的 512 個引用 4、返回的對象被認(rèn)為是只讀的,因此對它們進(jìn)行修改可能會在不同線程中的調(diào)用者產(chǎn)生沖突 --> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> <select id="findUserById" resultType="entity.User"> select * from user where id = #{id} </select> </mapper>
注意,如果是直接使用 <cache />,即不配置屬性,此時實體類即 User 類需要實現(xiàn)序列化 Serializable 接口。
測試代碼:
@Test public void test01() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = factory.openSession(); UserDao userDao = session.getMapper(UserDao.class); User user = userDao.findUserById(1); //需要手動提交事務(wù) session.commit(); session.close(); System.out.println("=======分隔符======="); SqlSession session2 = factory.openSession(); UserDao userDao2 = session2.getMapper(UserDao.class); User user2 = userDao2.findUserById(1); System.out.println(user == user2); }
日志輸出如下:

可以看到,在同一個 mapper 配置文件中的 SQL 語句,即使是不同的 sqlsession 對象,仍然可以命中緩存。
只有查詢才有緩存,我們可以根據(jù)數(shù)據(jù)是否需要緩存來配置該條查詢語句是否緩存:
<select id="getUserById" resultType="user" useCache="true"> select * from user where id = #{id} </select>
3.2、二級緩存的特性
二級緩存的特性:
-
開啟了二級緩存后,同一個Mapper中的相同 SQL 相同參數(shù)的查詢可以在二級緩存中拿到數(shù)據(jù)。
-
查出的數(shù)據(jù)都會被默認(rèn)先放在一級緩存中,只有會話提交或者關(guān)閉以后,一級緩存中的數(shù)據(jù)才會轉(zhuǎn)到二級緩存中。

浙公網(wǎng)安備 33010602011771號