MyBatis一級キャッシュおよび失効

23070 ワード

MyBatisはクエリーキャッシュメカニズムを提供し、大量の重複クエリーに対してキャッシュを使用することでデータベースの圧力を軽減します.
公式サイト
MyBatisには強力なトランザクション・クエリー・キャッシュ・メカニズムが内蔵されており、構成とカスタマイズが容易です.より強力で構成しやすいように、MyBatis 3のキャッシュ実装を大幅に改善しました.デフォルトでは、ローカルのセッションキャッシュのみが有効になり、1つのセッションのデータのみがキャッシュされます.グローバル2次キャッシュを有効にするには、SQLマッピングファイルに行を追加するだけです.
MyBatisの一級キャッシュはセッションベースであり,異なるセッション間で共有できない.2次キャッシュはnamespaceに基づいており、すべてのセッションを共有できます.
一級キャッシュテスト
一級キャッシュはデフォルトでオンであり、オフにすることはできません.
MyBatisのプロファイルはここには貼られていません.
DemoDao
public interface DemoDao {

	@Select("select * from t where a = 1")
	Map<String,Object> selectOne();

	@Update("update t set c = 2 where a = 1")
	int updateOne();
}

CacheDemo
public class CacheDemo {
	SqlSessionFactory factory;

	@Before
	public void init() throws IOException {
		String resource = "mybatis.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		factory = new SqlSessionFactoryBuilder().build(inputStream);
		if (inputStream != null) {
			inputStream.close();
		}
	}

	@Test
	public void test() throws IOException {
		SqlSession sqlSession = factory.openSession();
		System.out.println("     ...");
		select(sqlSession);
		System.out.println("     ...");
		update();
		System.out.println("     ...");
		select(sqlSession);
	}

	//select  
	void select(SqlSession session) throws IOException {
		DemoDao mapper = session.getMapper(DemoDao.class);
		Map<String, Object> map = mapper.selectOne();
		System.out.println(map);
	}

	//update  
	void update() throws IOException {
		SqlSession session = factory.openSession();
		DemoDao mapper = session.getMapper(DemoDao.class);
		mapper.updateOne();
		session.commit();
		session.close();
	}
}

出力は次のとおりです.
     ...
DEBUG [main] - ==>  Preparing: select * from t where a = 1 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: a, b, c
TRACE [main] - <==        Row: 1, 1, 1
DEBUG [main] - <==      Total: 1
{a=1, b=1, c=1}

     ...
DEBUG [main] - ==>  Preparing: update t set c = 2 where a = 1 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==    Updates: 1
DEBUG [main] - ==>  Preparing: select * from t where a = 1 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: a, b, c
TRACE [main] - <==        Row: 1, 1, 2
DEBUG [main] - <==      Total: 1

      :{a=1, b=1, c=2}

     ...
{a=1, b=1, c=1}

1回目のクエリと2回目のクエリは同じSqlSessionであり,2回のクエリの間にUPDATE操作が1回行われ,クエリのデータは依然として古い.
出力されたログからも、2回目のクエリはSQLを実行するのではなく、キャッシュから直接返される結果が表示されます.
Springと統合すると、1つのキャッシュが無効になりますか?
MyBatisを単独で使用する場合、SqlSessionの実装クラスはDefaultSqlSessionであり、Springと統合する場合、MyBatisはSqlSessionTemplate実装クラスを提供する.
SqlSessionTemplateには、SqlSessionInterceptorという内部クラスがあります.
ソースコードは次のとおりです.
private class SqlSessionInterceptor implements InvocationHandler {
        private SqlSessionInterceptor() {
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);

            Object unwrapped;
            try {
                Object result = method.invoke(sqlSession, args);
                if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
                    sqlSession.commit(true);
                }

                unwrapped = result;
            } catch (Throwable var11) {
                unwrapped = ExceptionUtil.unwrapThrowable(var11);
                if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                    SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                    sqlSession = null;
                    Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
                    if (translated != null) {
                        unwrapped = translated;
                    }
                }

                throw (Throwable)unwrapped;
            } finally {
                if (sqlSession != null) {
                    //     SQL,      sqlSession
                    SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                }

            }

            return unwrapped;
        }
    }

SQLを実行するたびに、SqlSessionInterceptorはsqlSessionを閉じます.
これにより、実行するたびにsqlSessionが異なり、一級キャッシュはsqlSessionに基づいており、キャッシュが失効し、毎回データベースからクエリーされます.