거의 바뀌지 않거나 고정된 값을 디비에서 자주 쿼리해야할 경우가 있다. 이때 마이바티스에서 제공하는 쿼리캐싱 기능 사용법을 알아보자.
작성일 : 2021-04-06
https://mybatis.org/mybatis-3/ko/sqlmap-xml.html#cache
공식문서에 잘 설명이 되어있다.
1> 캐싱적용시 고려해야하는 사항들
* flush / set 하는 시점을 명확히 정의 해야한다. --> 단순히 부하를 줄인다고 여기저기 사용했다가 갑자기 이상한 데이터로 에러가 발생할 수 있고 추적 또한 어렵다. * 마이바티스의 경우 쿼리 단위로 캐싱을 해줘 문제가 되지 않지만 Redis나 Memcached, ehcache등을 사용한다면 값저장시 키값을 잘 정의해야한다. --> 보통 키값에 prefix(객체명+'_')를 주어 구분한다. * 데이터가 자주 변경되는 경우 사용여부를 다시한번 고려해보자. --> 변경시 flush하고 확인시 다시 set해줘야 하기 때문에 불필요한 절차만 추가할 뿐이다.
2> 적용예제
<?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="com.opendocs.www.repository.categorys.CategorysDaoMapper">
<!-- Configuration Caching -->
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
<!-- Insert Query Flush Cache -->
<insert id="insert" parameterType="categorys">
INSERT INTO opendocs_www.categorys (uid, pid, name, status, created_at)
VALUES(#{uid}, #{pid}, #{name}, #{status}, now())
</insert>
<!-- Select Query Use Cache -->
<select id="select" parameterType="categorys" resultType="categorys">
SELECT uid, pid, name, status, created_at, updated_at
FROM opendocs_www.categorys T1
</select>
<!-- Update Query Flush Cache -->
<update id="update" parameterType="categorys">
UPDATE opendocs_www.categorys
<set>
<if test="1 == 1">updated_at = now(),</if>
<if test="pid != null">pid = #{pid},</if>
<if test="name != null">name = #{name},</if>
<if test="status != null">status = #{status},</if>
</set>
WHERE uid = #{uid}
</update>
<!-- Delete Query Flush Cache -->
<delete id="delete" parameterType="categorys">
DELETE FROM opendocs_www.categorys WHERE uid = #{uid}
</delete>
</mapper>
위의 예제는 select시 캐싱하고 insert, update, delete시 캐싱된 데이터를 지운다. <cache/>를 선언하게 되면 다음 속성을 선언한 것과 같으며 특정쿼리가 캐싱되지 않기를 원한다면 useCache="false"를 선언해주면 된다. <select ... flushCache="false" useCache="true"/> <insert ... flushCache="true"/> <update ... flushCache="true"/> <delete ... flushCache="true"/>
2-1> eviction : 캐싱전략
* LRU - 가장 오랜시간 사용하지 않는 객체를 제거 * FIFO - 캐시에 들어온 순서대로 객체를 제거 * SOFT - 가비지 컬렉터의 상태와 강하지 않은 참조(Soft References )의 규칙에 기초하여 객체를 제거 * WEAK - 가비지 컬렉터의 상태와 약한 참조(Weak References)의 규칙에 기초하여 점진적으로 객체 제거
2-2> flushInterval : 플러시 주기 (밀리세컨드 단위 1초 = 1000)
* 밀리세컨드 단위로 1초이면 1000 * 기본값없음 (미선언시 쿼리수행시만 동작)
2-3> size : 캐싱 사이즈
* 메모리 상황을 고려한 적정한 사이즈 * 기본값 1024
2-4> readOnly : 읽기전용 여부
* 모든 호출자에게 캐시된 객체의 같은 인스턴스(변경불가)를 리턴 * 사용시 성능 향상 * 기본값 false
3> 다른 캐싱방법
상황에 맞추어 아래 캐싱방법도 고려하여 보자.
- Memcached
- Redis
- ehcache