Mybatis 緩存
緩存的重要性是不言而喻的。使用緩存,我們可以避免頻繁地與資料庫進行互動,尤其是查詢越多,緩存命中率越高的情況下,使用緩存對性能的提高越是明顯。
Mybatis也提供了對緩存的支援,分為一級緩存和二級緩存。在預設的情況下,隻開啟了一級緩存,一級緩存是對同一個SqlSession而言的。
什麼是SqlSession?
概念
在Mybatis中,SqlSession 是其核心接口。在Mybatis中有兩個實作類,DefaultSqlSession 和SqlSessionManager。
DefaultSqlSession 是單線程使用的,而SqlSessionManager是多線程環境下使用的。
作用
SqlSession的作用類似于一個JDBC中的Connection 對象,代表了一個連接配接資源的啟用,具體而言有3個作用:
1、擷取Mapper接口;
2、發送SQL給資料庫;
3、控制資料庫事務;
建構
通過SqlSessionFactory建立SqlSession非常簡單,如下所示:
注意:SqlSession 隻是一個門面接口,他有很多的方法,可以直接發送SQL,在Mybatis中,真正幹活的是Executor。
事務控制
SqlSession控制資料庫事務的方法,如下所示:// 定義SqlSession SqlSession sqlSession=null; try{ // 打開SqlSession會話 sqlSession=SqlSessionFactory.openSession(); //execut sql sqlSession.commit(); //送出事務 }catch(IOException e){ sqlSession.rollback(); //復原事務 }finally{ // 在finally語句中確定資源被順利關閉 if(sqlSession!=null){ sqlSession.close(); } }
這裡是喲個commit方法送出事務或者使用rollback方法復原事務。
因為它代表了一個資料庫的連接配接資源,使用以後需要及時關閉它,如果不關閉資料庫的資源會很快被消耗完。
引用: http://c.biancheng.net/view/4316.html
一級緩存
同一個SqlSession對象,在參數和SQL完全相同的情況下,如果緩存沒有過期,則隻執行一次SQL語句。
注意:隻有在參數和SQL完全一樣的情況下,才會有這樣的情況。
示例一:相同的sqlSession重複查詢
測試用例:
@Test
public void testOneSqlSession() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println("first query...");
List<User> first = userMapper.listAll();
first.forEach(user -> System.out.println(user.toString()));
System.out.println("second query...");
List<User> second = userMapper.listAll();
second.forEach(user -> System.out.println(user.toString()));
Assert.assertEquals(first, second);
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
執行結果:
first query...
2021-04-01 11:46:01,036 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 11:46:01 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 11:46:01,507 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - ==> Preparing: SELECT ID,NAME FROM USER
2021-04-01 11:46:01,589 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - ==> Parameters:
2021-04-01 11:46:01,650 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Columns: ID, NAME
2021-04-01 11:46:01,651 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 1, 1
2021-04-01 11:46:01,652 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 2, 2
2021-04-01 11:46:01,653 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 3, 3
2021-04-01 11:46:01,653 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Total: 3
[email protected]
[email protected]
[email protected]
second query...
2021-04-01 11:46:01,656 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
[email protected]
com.xianyanyang.mybatis.en[email protected]
[email protected]
說明:
第一次查詢發送了查詢SQL語句後傳回了執行結果;
第二次查詢并未發送查詢SQL語句,從一級緩存中拿到資料。
從斷言中可以看出兩次查詢結果相同。
示例二:相同的sqlSession查詢,且修改了記憶體中的對象屬性
測試用例:
@Test
public void testOneSqlSession_changeMemory() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println("first query user...");
User user = userMapper.findUser("2");
user.setName("xiao xianxian");
System.out.println("second query user...");
User user2 = userMapper.findUser("2");
Assert.assertEquals("xiao xianxian",user2.getName());
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
執行結果:
first query user...
2021-04-01 14:32:53,711 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 14:32:53 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 14:32:54,158 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 14:32:54,220 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Parameters: 2(String)
2021-04-01 14:32:54,266 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Columns: ID, NAME
2021-04-01 14:32:54,266 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Row: 2, 2
2021-04-01 14:32:54,267 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Total: 1
second query user...
2021-04-01 14:32:54,268 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
說明:
說明:
第一次查詢向資料庫發送了SQL語句;
修改了緩存中的對象屬性;
第二次查詢未向資料庫發送SQL語句,而是從緩存中拿了上次的查詢結果對象,注意看,本次拿到的結果的姓名已經被修改。
示例三:不同的sqlSession分别查詢
測試用例:
@Test
public void testOneSqlSession() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println("first query...");
List<User> first = userMapper.listAll();
first.forEach(user -> System.out.println(user.toString()));
System.out.println("second query...");
List<User> second = userMapper.listAll();
second.forEach(user -> System.out.println(user.toString()));
Assert.assertEquals(first, second);
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
執行結果:
first query...
2021-04-01 11:47:55,168 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 11:47:55 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 11:47:55,627 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - ==> Preparing: SELECT ID,NAME FROM USER
2021-04-01 11:47:55,711 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - ==> Parameters:
2021-04-01 11:47:55,755 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Columns: ID, NAME
2021-04-01 11:47:55,755 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 1, 1
2021-04-01 11:47:55,756 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 2, 2
2021-04-01 11:47:55,757 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 3, 3
2021-04-01 11:47:55,757 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Total: 3
[email protected]
[email protected]
[email protected]
second query...
2021-04-01 11:47:55,759 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
[email protected]
com.xianyanyang.mybatis.en[email protected]
[email protected]
說明:
說明:
第一次查詢發送了查詢SQL語句後傳回了執行結果;
第二次查詢并未發送查詢SQL語句,而是從記憶體中傳回了緩存後的執行結果;
從斷言中可以看出兩次查詢結果的值雖然相同,但是是屬于不同的對象。
示例四:相同的sqlSession關閉了緩存
測試用例:
<select id="findById" flushCache="true" parameterType="java.lang.String" resultMap="User">
SELECT ID,NAME FROM USER WHERE ID=#{id, jdbcType=VARCHAR}
</select>
@Test
public void nocache() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println("first query...");
User first = userMapper.findById("1");
System.out.println(first.toString());
System.out.println("second query...");
User second = userMapper.findById("1");
System.out.println(second.toString());
Assert.assertNotEquals(first, second);
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
執行結果:
first query...
2021-04-01 11:57:15,075 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 11:57:15 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 11:57:15,814 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findById] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 11:57:15,883 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findById] - ==> Parameters: 1(String)
2021-04-01 11:57:15,949 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findById] - <== Columns: ID, NAME
2021-04-01 11:57:15,949 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findById] - <== Row: 1, 1
2021-04-01 11:57:15,950 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findById] - <== Total: 1
[email protected]
second query...
2021-04-01 11:57:15,951 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
2021-04-01 11:57:15,951 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findById] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 11:57:15,951 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findById] - ==> Parameters: 1(String)
2021-04-01 11:57:15,963 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findById] - <== Columns: ID, NAME
2021-04-01 11:57:15,963 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findById] - <== Row: 1, 1
2021-04-01 11:57:15,963 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findById] - <== Total: 1
[email protected]
說明:
在userMapper.xml中設定了該查詢語句的配置項flushCache="true"後,緩存失效。兩次查詢均是發送了sql語句進行了查詢,查詢的兩次結果也都是不同的對象。
示例五:執行查詢過程中執行了update語句
測試用例:
執行結果:
first query...
2021-04-01 13:59:35,154 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 13:59:35 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 13:59:35,602 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - ==> Preparing: SELECT ID,NAME FROM USER
2021-04-01 13:59:35,680 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - ==> Parameters:
2021-04-01 13:59:35,721 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Columns: ID, NAME
2021-04-01 13:59:35,721 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 1, 1
2021-04-01 13:59:35,723 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 2, 2
2021-04-01 13:59:35,723 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 3, 3
2021-04-01 13:59:35,723 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Total: 3
[email protected]
[email protected]
[email protected]
second query...
2021-04-01 13:59:35,725 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
[email protected]
[email protected]
[email protected]
update...
2021-04-01 13:59:35,730 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.changeUserName] - ==> Preparing: UPDATE USER SET NAME=? WHERE ID=?
2021-04-01 13:59:35,731 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.changeUserName] - ==> Parameters: 2222(String), 1(String)
2021-04-01 13:59:35,753 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.changeUserName] - <== Updates: 1
third query...
2021-04-01 13:59:35,753 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
2021-04-01 13:59:35,753 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - ==> Preparing: SELECT ID,NAME FROM USER
2021-04-01 13:59:35,753 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - ==> Parameters:
2021-04-01 13:59:35,775 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Columns: ID, NAME
2021-04-01 13:59:35,775 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 1, 2222
2021-04-01 13:59:35,776 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 2, 2
2021-04-01 13:59:35,776 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Row: 3, 3
2021-04-01 13:59:35,776 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.listAll] - <== Total: 3
[email protected]
com.xianyanyang.mybatis.en[email protected]
[email protected]
說明:
第一次查詢發送了查詢SQL語句後傳回了執行結果;
第二次查詢并未發送查詢SQL語句,而是從記憶體中傳回了緩存後的執行結果;
執行了修改的sql語句後第三次查詢,緩存失效,依舊進行了SQL語句的資料庫查詢。
總結
1、開啟了一級緩存後,緩存範圍為會話級别,同一個sqlsession下,查詢命中一級緩存記憶體資料;
2、不同的 SqlSession 之間的緩存是互相隔離的;
3、用一個 SqlSession, 可以通過配置使得在查詢前清空緩存;
4、執行了 UPDATE, INSERT, DELETE 語句後,一級緩存失效。
二級緩存
二級緩存存在于SqlSessionFactory生命周期中。二級緩存開啟後,同一個namespace下的所有操作語句,都影響着同一個Cache,即二級緩存被多個SqlSession共享,是一個全局的變量。當開啟緩存後,資料的查詢執行的流程就是 二級緩存 -> 一級緩存 -> 資料庫。
配置
要正确的使用二級緩存,需完成如下配置的。
1、在MyBatis的配置檔案中開啟二級緩存。
2、在MyBatis的映射XML中配置cache或者 cache-ref 。
cache标簽用于聲明這個namespace使用二級緩存,并且可以自定義配置。
- type:cache使用的類型,預設是PerpetualCache,這在一級緩存中提到過。
- eviction: 定義回收的政策,常見的有FIFO,LRU。
- flushInterval: 配置一定時間自動重新整理緩存,機關是毫秒。
- size: 最多緩存對象的個數。
- readOnly: 是否隻讀,若配置可讀寫,則需要對應的實體類能夠序列化。
- blocking: 若緩存中找不到對應的key,是否會一直blocking,直到有對應的資料進入緩存。
示例一:
測試二級緩存效果,sqlSession1查詢完資料後關閉會話,sqlSession2相同的查詢是否會從緩存中擷取資料。
測試用例:
@Test
public void secondCache_differentSqlSession_close() {
System.out.println("first query...");
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
User first = userMapper1.findUser("1");
first.setName("xiaoxianxian");
System.out.println(first + " ->name:" + first.getName());
sqlSession1.close();
System.out.println("second query...");
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User second = userMapper2.findUser("1");
System.out.println(second + " ->name:" + second.getName());
Assert.assertEquals(second.getName(), "xiaoxianxian");
sqlSession2.close();
}
執行結果:
first query...
2021-04-01 16:13:03,329 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 16:13:03 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 16:13:03,798 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 16:13:03,878 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Parameters: 1(String)
2021-04-01 16:13:03,926 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Columns: ID, NAME
2021-04-01 16:13:03,926 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Row: 1, foo
2021-04-01 16:13:03,927 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Total: 1
[email protected] ->name:xiaoxianxian
second query...
2021-04-01 16:13:03,941 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.5
com.[email protected] ->name:xiaoxianxian
說明:
開啟了二級緩存後,sqlsession1查詢完成資料後,執行close,sqlsession2相同的查詢會命中二級緩存。
示例二:
測試二級緩存效果,不關閉會話也不送出事務,sqlSession1查詢完資料後,sqlSession2相同的查詢是否會從緩存中擷取資料。
測試用例:
@Test
public void secondCache_differentSqlSession_noCommit() {
SqlSession sqlSession1 = null;
SqlSession sqlSession2 = null;
UserMapper userMapper1;
UserMapper userMapper2;
try {
System.out.println("first query...");
sqlSession1 = sqlSessionFactory.openSession();
userMapper1 = sqlSession1.getMapper(UserMapper.class);
User first = userMapper1.findUser("1");
first.setName("xiaoxianxian");
System.out.println(first + " ->name:" + first.getName());
System.out.println("second query...");
sqlSession2 = sqlSessionFactory.openSession();
userMapper2 = sqlSession2.getMapper(UserMapper.class);
User second = userMapper2.findUser("1");
System.out.println(second + " ->name:" + second.getName());
Assert.assertNotEquals(second.getName(), "xiaoxianxian");
} finally {
if (sqlSession1 != null) {
sqlSession1.close();
}
if (sqlSession2 != null) {
sqlSession2.close();
}
}
}
執行結果:
first query...
2021-04-01 15:29:07,802 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 15:29:08 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 15:29:08,293 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 15:29:08,351 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Parameters: 1(String)
2021-04-01 15:29:08,398 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Columns: ID, NAME
2021-04-01 15:29:08,398 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Row: 1, 1
2021-04-01 15:29:08,400 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Total: 1
[email protected] ->name:xiaoxianxian
second query...
2021-04-01 15:29:08,401 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 15:29:08 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 15:29:08,540 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 15:29:08,540 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Parameters: 1(String)
2021-04-01 15:29:08,552 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Columns: ID, NAME
2021-04-01 15:29:08,552 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Row: 1, 1
2021-04-01 15:29:08,553 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Total: 1
[email protected] ->name:1
說明:
開啟了二級緩存後,sqlSession1查詢完語句後,沒有進行會話結束也沒有送出事務,則二級緩存不生效,sqlSession2查詢無法命中緩存。
示例三:
測試二級緩存效果,當送出事務時,sqlSession1查詢完資料後,sqlSession2相同的查詢是否會從緩存中擷取資料。
測試用例:
<cache readOnly="false"/>
@Test
public void secondCache_differentSqlSession_commited() {
SqlSession sqlSession1 = null;
SqlSession sqlSession2 = null;
UserMapper userMapper1;
UserMapper userMapper2;
try {
System.out.println("first query...");
sqlSession1 = sqlSessionFactory.openSession();
userMapper1 = sqlSession1.getMapper(UserMapper.class);
User first = userMapper1.findUser("1");
first.setName("xiaoxianxian");
System.out.println(first + " ->name:" + first.getName());
System.out.println("second query...");
sqlSession1.commit();
sqlSession2 = sqlSessionFactory.openSession();
userMapper2 = sqlSession2.getMapper(UserMapper.class);
User second = userMapper2.findUser("1");
System.out.println(second + " ->name:" + second.getName());
Assert.assertEquals(second.getName(), "xiaoxianxian");
} finally {
if (sqlSession1 != null) {
sqlSession1.close();
}
if (sqlSession2 != null) {
sqlSession2.close();
}
}
}
執行結果:
first query...
2021-04-01 15:33:04,150 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 15:33:04 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 15:33:04,602 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 15:33:04,670 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Parameters: 1(String)
2021-04-01 15:33:04,708 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Columns: ID, NAME
2021-04-01 15:33:04,708 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Row: 1, 1
2021-04-01 15:33:04,710 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Total: 1
[email protected] ->name:xiaoxianxian
second query...
2021-04-01 15:33:04,722 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.5
com.[email protected] ->name:xiaoxianxian
說明:
開啟了二級緩存後,sqlSession1查詢完成後,執行了事務的送出,則二級緩存生效,sqlsession2的查詢會命中緩存,緩存的命中率是0.5。
注意:
[email protected] ->name:xiaoxianxian
[email protected] ->name:xiaoxianxian
命中的結果對象和之前的不是一個對象,是因為配置了:
<cache readOnly="false"/>
readOnly 為隻讀屬性,預設為 false
false: 可讀寫,在建立對象時,會通過反序列化得到緩存對象的拷貝。是以在速度上會相對慢一點,但重在安全。
true: 隻讀,隻讀的緩存會給所有調用者傳回緩存對象的相同執行個體。是以性能很好,但如果修改了對象,有可能會導緻程式出問題。
如果配置了readOnly="true",執行結果為:
[email protected] ->name:xiaoxianxian
com.[email protected] ->name:xiaoxianxian
示例四:
測試update操作是否會重新整理該namespace下的二級緩存。
測試用例:
@Test
public void secondCacheDifferentSqlSessionWithUpdate() {
SqlSession sqlSession1 = null;
SqlSession sqlSession2 = null;
SqlSession sqlSession3 = null;
UserMapper userMapper1;
UserMapper userMapper2;
UserMapper userMapper3;
try {
System.out.println("first query...");
sqlSession1 = sqlSessionFactory.openSession();
userMapper1 = sqlSession1.getMapper(UserMapper.class);
User first = userMapper1.findUser("1");
first.setName("xiaoxianxian");
System.out.println(first + " ->name:" + first.getName());
sqlSession1.commit();
System.out.println("second query...");
sqlSession2 = sqlSessionFactory.openSession();
userMapper2 = sqlSession2.getMapper(UserMapper.class);
User second = userMapper2.findUser("1");
System.out.println(second + " ->name:" + second.getName());
System.out.println("update user...");
sqlSession3 = sqlSessionFactory.openSession(true);
userMapper3 = sqlSession3.getMapper(UserMapper.class);
userMapper3.changeUserName("1", "foo");
sqlSession3.commit();
System.out.println("third query...");
User third = userMapper2.findUser("1");
System.out.println(third + " ->name:" + third.getName());
} finally {
if (sqlSession1 != null) {
sqlSession1.close();
}
if (sqlSession2 != null) {
sqlSession2.close();
}
if (sqlSession3 != null) {
sqlSession3.close();
}
}
}
執行結果:
first query...
2021-04-01 15:53:26,016 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.0
Thu Apr 01 15:53:26 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 15:53:26,488 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 15:53:26,558 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Parameters: 1(String)
2021-04-01 15:53:26,609 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Columns: ID, NAME
2021-04-01 15:53:26,609 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Row: 1, foo
2021-04-01 15:53:26,611 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Total: 1
[email protected] ->name:xiaoxianxian
second query...
2021-04-01 15:53:26,623 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.5
[email protected] ->name:xiaoxianxian
update user...
Thu Apr 01 15:53:26 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 15:53:26,770 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.changeUserName] - ==> Preparing: UPDATE USER SET NAME=? WHERE ID=?
2021-04-01 15:53:26,770 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.changeUserName] - ==> Parameters: foo(String), 1(String)
2021-04-01 15:53:26,794 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.changeUserName] - <== Updates: 1
third query...
2021-04-01 15:53:26,795 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper] - Cache Hit Ratio [com.xianyanyang.mybatis.mapper.UserMapper]: 0.3333333333333333
Thu Apr 01 15:53:26 CST 2021 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2021-04-01 15:53:26,934 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Preparing: SELECT ID,NAME FROM USER WHERE ID=?
2021-04-01 15:53:26,934 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - ==> Parameters: 1(String)
2021-04-01 15:53:26,945 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Columns: ID, NAME
2021-04-01 15:53:26,945 [main] TRACE [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Row: 1, foo
2021-04-01 15:53:26,945 [main] DEBUG [com.xianyanyang.mybatis.mapper.UserMapper.findUser] - <== Total: 1
[email protected] ->name:foo
說明:
在sqlSession3更新資料庫,并送出事務後,sqlsession2的查詢走了資料庫,沒有走Cache。
參考:
https://blog.csdn.net/weixin_37139197/article/details/82908377
https://blog.csdn.net/bjweimengshu/article/details/79988252