Mybatis 一級快取和引發的問題

小賊驢發表於2019-06-20

1.Mybatis 是預設開啟一級快取的。跟Spring結合使用的話執行的方法必須開啟事務一級快取才有效。
2.當查詢資料時候,先從快取中尋找是否存在該條資料,存在就直接取出來,不存在,向資料庫傳送sql查詢, 然後將查詢後的資料存入快取返回給程式。

下邊圍繞著如下幾個問題展開驗證:

  1. 開啟事務,一級快取有效
  2. 不開啟事務,一級快取失效
  3. Mybatis一級快取的坑在哪呢?
  4. 驗證一個事物中進行insert update delete 會重新整理一級快取

二 驗證

1.開啟事務,一級快取有效。從日誌看到確實只執行了一次查詢。


@Test
@Transactional
public void test() {
	LangUser langUser = langUserMapper.selectByPrimaryKey(-1);
	LangUser langUser1 = langUserMapper.selectByPrimaryKey(-1);
	LangUser langUser2 = langUserMapper.selectByPrimaryKey(-1);

}
15:58:20.584 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
15:58:20.594 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63648ee9]
15:58:21.095 [main] WARN  com.alibaba.druid.pool.DruidDataSource - removeAbandoned is true, not use in productiion.
15:58:21.872 [main] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
15:58:21.899 [main] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@4351171a] will be managed by Spring
15:58:21.902 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==>  Preparing: select ID, NAME, AGE, SCORE from LANG_USER where ID = ? 
15:58:21.974 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==> Parameters: -1(Integer)
15:58:22.013 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==    Columns: ID, NAME, AGE, SCORE
15:58:22.020 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==        Row: -1, 小狼, 18, 100
15:58:22.022 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==      Total: 1
15:58:22.024 [main] DEBUG com.alibaba.druid.pool.PreparedStatementPool - {conn-10004, pstmt-20000} enter cache

2.不開啟事務,一級快取失效

@Test
public void test() {
	LangUser langUser = langUserMapper.selectByPrimaryKey(-1);
	LangUser langUser1 = langUserMapper.selectByPrimaryKey(-1);
	LangUser langUser2 = langUserMapper.selectByPrimaryKey(-1);
}

注意看日誌列印,下面這句話執行了出現了三次,每一次查詢都建立了一個sqlSeesion,sql也執行了三次。

16:02:29.606 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession

16:02:29.606 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
16:02:29.612 [main] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4c6daf0] was not registered for synchronization because synchronization is not active
16:02:29.863 [main] WARN  com.alibaba.druid.pool.DruidDataSource - removeAbandoned is true, not use in productiion.
16:02:31.175 [main] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
16:02:31.224 [main] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3088660d] will not be managed by Spring
16:02:31.230 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==>  Preparing: select ID, NAME, AGE, SCORE from LANG_USER where ID = ? 
16:02:31.335 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==> Parameters: -1(Integer)
16:02:31.397 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==    Columns: ID, NAME, AGE, SCORE
16:02:31.409 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==        Row: -1, 小狼, 18, 100
16:02:31.413 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==      Total: 1
16:02:31.414 [main] DEBUG com.alibaba.druid.pool.PreparedStatementPool - {conn-10004, pstmt-20000} enter cache
16:02:31.417 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4c6daf0]
16:02:31.420 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
16:02:31.422 [main] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@272a179c] was not registered for synchronization because synchronization is not active
16:02:31.423 [main] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3088660d] will not be managed by Spring
16:02:31.425 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==>  Preparing: select ID, NAME, AGE, SCORE from LANG_USER where ID = ? 
16:02:31.426 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==> Parameters: -1(Integer)
16:02:31.430 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==    Columns: ID, NAME, AGE, SCORE
16:02:31.430 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==        Row: -1, 小狼, 18, 100
16:02:31.431 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==      Total: 1
16:02:31.435 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@272a179c]
16:02:31.435 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
16:02:31.437 [main] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@67207d8a] was not registered for synchronization because synchronization is not active
16:02:31.438 [main] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3088660d] will not be managed by Spring
16:02:31.439 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==>  Preparing: select ID, NAME, AGE, SCORE from LANG_USER where ID = ? 
16:02:31.442 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==> Parameters: -1(Integer)
16:02:31.444 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==    Columns: ID, NAME, AGE, SCORE
16:02:31.444 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==        Row: -1, 小狼, 18, 100
16:02:31.444 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==      Total: 1
16:02:31.445 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@67207d8a]
16:02:31.480 [Thread-1] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-0} closing ...
16:02:31.484 [Thread-1] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-1} closing ...
16:02:31.589 [Thread-1] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-1} closed

3.坑在哪呢?我們看這種開啟事務的情況。

第一次查詢後,我只是把查詢出來的物件賦值“喜洋洋”,我並沒有跟資料庫有任何互動,下面的兩次查詢結果竟然修改後的“喜洋洋”。

@Test
@Transactional
public void test() {
	LangUser langUser = langUserMapper.selectByPrimaryKey(-1);
	logger.info("姓名:"+langUser.getName());
	langUser.setName("喜洋洋");
	LangUser langUser1 = langUserMapper.selectByPrimaryKey(-1);
	logger.info("姓名:"+langUser1.getName());
	LangUser langUser2 = langUserMapper.selectByPrimaryKey(-1);
	logger.info("姓名:"+langUser2.getName());
}
16:16:22.983 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
16:16:22.991 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@117e0fe5]
16:16:23.437 [main] WARN  com.alibaba.druid.pool.DruidDataSource - removeAbandoned is true, not use in productiion.
16:16:24.423 [main] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
16:16:24.459 [main] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3c2772d1] will be managed by Spring
16:16:24.463 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==>  Preparing: select ID, NAME, AGE, SCORE from LANG_USER where ID = ? 
16:16:24.575 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - ==> Parameters: -1(Integer)
16:16:24.604 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==    Columns: ID, NAME, AGE, SCORE
16:16:24.612 [main] TRACE com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==        Row: -1, 小狼, 18, 100
16:16:24.615 [main] DEBUG com.hao.xu.lang.mapper.oracle.LangUserMapper.selectByPrimaryKey - <==      Total: 1
16:16:24.617 [main] DEBUG com.alibaba.druid.pool.PreparedStatementPool - {conn-10004, pstmt-20000} enter cache
16:16:24.618 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@117e0fe5]
16:16:24.618 [main] INFO  com.hao.xu.lang.mapper.oracle.LangUserMapperTest - 姓名:小狼
16:16:24.620 [main] INFO  com.hao.xu.lang.mapper.oracle.LangUserMapperTest - 姓名:喜洋洋
16:16:24.621 [main] INFO  com.hao.xu.lang.mapper.oracle.LangUserMapperTest - 姓名:喜洋洋
16:16:24.622 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@117e0fe5]
16:16:24.623 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@117e0fe5]

原因:
當資料庫建立一次連線,就會建立一個SqlSession物件,預設是DefaultSqlSession這個實現,這個物件給使用者提供了運算元據庫的各種方法,與此同時,也會建立一個Executor執行器,快取資訊就是維護在Executor中,如果這個sqlSessio進行
insert update delete 它會釋放掉Executor中的快取

4.驗證一個事物中進行insert update delete 會重新整理一級快取

@Test
@Transactional
public void test() {
	LangUser langUser = langUserMapper.selectByPrimaryKey(-1);
	logger.info("姓名:"+langUser.getName());
	langUser.setName("喜洋洋");

    //新建物件插入表中,讓sqlsession 有提交動作
	LangUser langUser3 = new LangUser();
	langUser3.setName("紅太狼");
	langUser3.setAge(5);
	langUser3.setScore("90");
	langUserMapper.insert(langUser3);

	LangUser langUser1 = langUserMapper.selectByPrimaryKey(-1);
	logger.info("姓名:"+langUser1.getName());
	LangUser langUser2 = langUserMapper.selectByPrimaryKey(-1);
	logger.info("姓名:"+langUser2.getName());
}

分析下console 其中有寫日誌我刪除了為了方便大家閱讀:
在這裡插入圖片描述

相關文章