목차
첫 번째 섹션 Mybatis 캐시
1.1 Mybatis 캐시 이해
- Mybatis의 캐시는 첫 번째 수준 캐시와 두 번째 수준 캐시를 포함하여 최대 절전 모드의 캐시와 유사 합니다 . 첫 번째 수준 캐시는 기본적으로 사용되며 두 번째 수준 캐시는 수동으로 켜야합니다.
- 1 단계 캐시는 sqlsession을 의미하며 sqlsession에는 맵 구조 인 데이터 영역이 있으며,이 영역은 1 단계 캐시 영역입니다. 첫 번째 레벨 캐시의 키는 SQL 문, 조건 및 명령문과 같은 정보로 구성된 고유 한 값입니다. 첫 번째 수준 캐시의 값은 쿼리의 결과 개체입니다.
- 2 단계 캐시는 동일한 네임 스페이스 아래의 매퍼를 의미하며 2 단계 캐시에는 맵 구조도 있으며이 영역은 1 단계 캐시 영역입니다.
sqlSession1에서 데이터 일부를 가져 오면 SQL을 사용하지 않고 sqlSession2에서 동일한 데이터를 가져올 수 있으며 이때 보조 캐시를 사용해야합니다.
보조 캐시는 모든 sqlSessions에서 공유됩니다.
1.2 레벨 1 캐시
원리
- 첫 번째 질의의 경우 id가 1 인 사용자가 sql을 실행하고 기본적으로 1 차 캐시가 수행되며 1 차 캐시 맵에 데이터가 저장되며, 사용자 수정, 추가, 삭제가 제출되면 1 차 캐시는 지워진다. , ID가 1 인 사용자를 다시 쿼리하고 sql을 다시 실행해야합니다.
사용 및 테스트
- 이전 save 및 findUserById 메소드
- 직렬화 인터페이스 (즉, 직렬화 가능 플래그)를 구현하도록 구성 할 클래스를 확인하십시오. 그렇지 않으면 오류가보고됩니다.
@Test
public void test1() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//4.通过会话获取dao接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//第二次不会执行sql
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
- 저장, 업데이트, 삭제 등이 포함되면 첫 번째 수준 캐시가 자동으로 지워집니다.
@Test
public void test2() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
//4.通过会话获取dao接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//保存一个新用户
userMapper.save(new User("shu1","男",new Date(),"北京市"));
//若要保存到数据库记得提交事务,否则不影响数据库,这里只做演示一级缓存可不提交
sqlSession.commit();
//此时第二次会执行sql
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
1.3 보조 캐시
원리
사용 및 테스트
- 보조 캐시의 일반 스위치를 켭니다 (글로벌 구성 파일에 구성됨) (더 많은 설정은 day01에 설정 됨).
- UserMapper.xml에서 보조 캐시 구성
- 테스트
- 직렬화 인터페이스 (즉, 직렬화 가능 플래그)를 구현하도록 구성 할 클래스를 확인하십시오. 그렇지 않으면 오류가보고됩니다.
//二级缓存
@Test
public void test3() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
//4.通过会话获取dao接口
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//session关闭了,数据才会写入二级缓存
sqlSession1.close();
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
- 삽입, 업데이트, 삭제 등의 작업을 수행하면 보조 캐시가 지워집니다.
@Test
public void test4() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
SqlSession sqlSession3 = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
//4.通过会话获取dao接口
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
sqlSession1.close();
//保存用户,二级缓存也会清空
userMapper3.save(new User("shu2","男",new Date(),"上海市"));
sqlSession3.commit();
sqlSession3.close();
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
지정된 메서드의 두 번째 수준 캐시 비활성화
- 지정된 메서드의 두 번째 수준 캐시가 비활성화되고이 메서드의 두 번째 수준 캐시가 적용되지 않으며 다른 메서드는 영향을주지 않습니다.
캐시 새로 고침
- 지정된 메서드의 두 번째 수준 캐시가 위에서 비활성화되어 있습니다.이 메서드는 두 번째 수준 캐시를 반영하는 데 사용됩니다. 비활성화를 제거해야합니다. 그렇지 않으면 캐시가 새로 고쳐지지 않습니다.
요약하자면
첫 번째 수준 캐시와 두 번째 수준 캐시의 공통점 : 삽입, 업데이트 및 삭제와 같은 작업을 수행하면 캐시가 지워집니다.
1.4 ehcache 통합
- 질문 : Mybatis와 함께 제공되는 캐시를 사용하지 않고 ehcache 캐시를 통합하는 이유는 무엇입니까?
- 답변 : Mybatis 자체는 지속성 계층 프레임 워크이며 전용 캐싱 프레임 워크가 아니므로 캐싱 구현은 분산을 지원하기에 충분하지 않지만 Ehcache는 분산 캐싱 프레임 워크입니다.
배포되는 항목
- 성능 향상을 위해 시스템은 일반적으로 분산 배포 (클러스터 배포)를 채택합니다.
통합 사고
- 캐시에는 표준화 된 인터페이스 캐시 (사용하고 싶은 사람, 구현하고 해당 메서드 작성)가 있으며 기본 구현은 mybatis의 PerpetualCache입니다. mybatis의 보조 캐시를 통합하려면 캐시 인터페이스를 구현하십시오.
- Mybatis는 구현 캐시와 함께 제공됩니다.
통합 단계
1 단계 : jar 패키지 가져 오기
- ehcache에서 구현 한 캐시를 볼 수 있습니다.
2 단계 : 매핑 파일에서 캐시 태그 구성
<!--配置缓存
type不写,默认使用的就是mybatis自带的缓存技术,perpetualCache永久缓存
-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
3 단계 : src 아래에 ehcache 구성 파일 추가
-
src 디렉토리에 복사하고 ehcache.xml로 이름을 바꿉니다 (주석 삭제 후).
-
maxElementsInMemory : 메모리 기반 캐시에 저장할 수있는 최대 개체 수를 설정합니다.
-
eternal : 개체가 영구적인지 여부를 설정합니다. true는 만료되지 않음을 의미하고, false이면 timeToIdleSeconds 및 timeToLiveSeconds에 따라 판단해야합니다.
-
timeToIdleSeconds : 개체가 유휴 상태가되는 최대 시간 (초)을 설정합니다.이 시간이 지나면 개체가 만료됩니다. 객체가 만료되면 EHCache는 캐시에서 객체를 제거합니다. 이 값이 0이면 개체가 무기한 유휴 상태 일 수 있음을 의미합니다. (단위는 초)
-
timeToLiveSeconds : 개체가 유지되는 가장 긴 시간을 설정합니다.이 시간이 지나면 개체가 만료됩니다. 이 값이 0이면 개체가 캐시에 무기한 존재할 수 있음을 의미합니다. 속성 값은 timeToIdleSeconds 속성 값 (초) 보다 크거나 같아야합니다.
-
overflowToDisk : 내부 캐시의 개체 수가 상한에 도달 한 후 오버플로 개체를 하드 디스크 기반 캐시에 쓸지 여부를 설정합니다.
-
diskPersistent : jvm이 종료 될 때 객체 (하드 디스크에 저장 됨)를 유지할지 여부, true 또는 false는 선택 사항이며 기본값은 false입니다.
-
diskExpiryThreadIntervalSeconds : 만료 된 개체 지우기 전용 수신 스레드의 폴링 시간을 지정합니다. (단위는 초)
-
memoryStoreEvictionPolicy : 메모리 캐시가 최대 값에 도달하고 새 요소가 추가되면 캐시의 요소가 디스크에서 제거 될 때의 정책입니다. 기본값은 LRU (최근에 가장 적게 사용됨), 옵션은 LFU (가장 적게 사용됨, 가장 적게 사용됨) 및 FIFO (선입 선출)입니다.
-
LRU (최근에 가장 적게 사용 된 항목) : 캐시 된 요소에 타임 스탬프가 있습니다. 캐시 용량이 가득 차서 새 요소를 캐시 할 공간을 확보해야하는 경우 타임 스탬프가 현재 시간에서 가장 먼 기존 캐시 요소의 요소 캐시에서 지워집니다.
-
LFU (덜 자주 사용됨) : 캐시 된 요소에 적중 속성이 있으며 적중 값이 가장 작은 요소가 캐시에서 지워집니다.
4 단계 : 테스트
- 이전 테스트 보조 캐시 사용
//二级缓存
@Test
public void test3() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
//4.通过会话获取dao接口
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//session关闭了,数据才会写入二级缓存
sqlSession1.close();
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
- SQL을 한 번 실행하고 두 번째로 두 번째 수준 캐시에서 가져옵니다.
1.5 보조 캐시의 사용 시나리오
- 높은 액세스 응답 속도가 필요하지만 실시간 성능이 낮은 쿼리의 경우 보조 캐시 기술을 사용할 수 있습니다 .
참고 : 2 단계 캐시를 사용하는 경우 2 단계 캐시를 정기적으로 새로 고치려면 새로 고침 간격 (캐시 태그에 flashInterval 속성이 있음)을 설정해야합니다.이 새로 고침 간격은 30 분, 60 분 등과 같은 특정 요구 사항에 따라 설정됩니다. 밀리 초입니다. - 예 : 캐시 새로 고침 간격을 60 분으로 설정 (60 분마다 캐시 지우기)
1.6 두 번째 레벨 캐시의 한계
-
Mybatis 2 단계 캐시는 세분화 된 데이터에 대해 제대로 구현되지 않았습니다.
-
예 : 제품 정보 캐시. 제품 정보 조회 방문량이 많기 때문에 사용자는 매번 최신 제품 정보를 조회해야합니다. 이때 2 차 캐시를 사용하는 경우 제품 변경시 캐시 된 제품 정보 만 새로 고칠 수 없습니다. 2 차 캐시가 매퍼 수준이기 때문에 다른 제품 캐시 정보를 새로 고치지 않으며, 제품 정보가 업데이트되면 모든 제품의 정보 캐시 데이터가 지워집니다.
-
이러한 문제를 해결하려면 데이터를 필요에 따라 비즈니스 계층에서 대상 방식으로 캐시해야합니다.
-
예를 들어 자주 변경되는 데이터에 대한 작업을 다른 네임 스페이스의 매퍼에 별도로 배치 할 수 있습니다.