캐싱 솔루션을 작성하지 마십시오

데이터베이스 작업 속도를 높이는 또 다른 방법은 이전에 이미 요청한 개체를 캐시하는 것입니다.

중요한! 자체 캐싱 솔루션을 작성하지 마십시오. 이 작업에는 꿈도 꾸지 못한 함정이 너무 많습니다.

문제 1 - 캐시 플러시 . 개체를 캐시에서 제거하거나 캐시에서 업데이트해야 할 때 이벤트가 발생하는 경우가 있습니다. 이를 유능하게 수행하는 유일한 방법은 캐시 엔진을 통해 모든 요청을 데이터베이스로 전달하는 것입니다. 그렇지 않으면 매번 삭제하거나 업데이트해야 하는 개체를 캐시에 명시적으로 알려야 합니다.

문제 2 - 메모리 부족 . 캐싱은 메모리의 개체가 많은 공간을 차지한다는 것을 알기 전까지는 좋은 생각처럼 보입니다. 서버 애플리케이션 캐시가 효과적으로 작동하려면 추가로 수십 기가바이트의 메모리가 필요합니다.

그리고 항상 메모리가 부족하기 때문에 캐시에서 개체를 삭제하는 효과적인 전략이 필요합니다. 이는 Java의 가비지 수집기와 다소 유사합니다. 그리고 당신이 기억하듯이, 수십 년 동안 최고의 지성인들은 세대별로 물체를 표시하는 다양한 방법을 발명해 왔습니다.

문제 3 - 다른 전략 . 실습에서 알 수 있듯이 캐시에 저장하고 업데이트하는 다양한 전략이 다양한 개체에 효과적입니다. 효율적인 캐싱 시스템은 모든 개체에 대해 단 하나의 전략을 수행할 수 없습니다.

문제 4 - . 캐시에 객체를 저장할 수는 없습니다. 개체에 다른 개체에 대한 참조가 너무 자주 포함되는 등 이 속도에서는 가비지 수집기가 필요하지 않습니다. 제거할 항목이 없을 뿐입니다.

따라서 개체 자체를 저장하는 대신 기본 필드의 값을 저장하는 것이 훨씬 더 효율적인 경우가 있습니다. 그리고 이를 기반으로 물체를 빠르게 구성하는 시스템.

결과적으로 전체 가상 DBMS가 메모리에 저장되어 신속하게 작동하고 메모리를 거의 사용하지 않습니다.

데이터베이스 캐싱

Java 프로그램에서 직접 캐싱하는 것 외에도 캐싱은 종종 데이터베이스에서 직접 구성됩니다.

네 가지 큰 접근 방식이 있습니다.

첫 번째 접근 방식은 데이터베이스를 비정규화하는 것 입니다 . SQL 서버는 데이터를 테이블에 저장하는 방식과 다르게 메모리에 저장합니다.

데이터가 디스크의 테이블에 저장될 때 개발자는 가능한 한 데이터 중복을 피하려고 하는 경우가 많습니다. 이 프로세스를 데이터베이스 정규화라고 합니다. 따라서 메모리의 데이터 작업 속도를 높이기 위해 데이터베이스 비정규화라는 역 프로세스가 수행됩니다. 관련 테이블 묶음은 거대한 테이블 등의 형태로 결합된 형태로 이미 저장될 수 있습니다.

두 번째 방법은 쿼리 캐싱 입니다 . 그리고 쿼리 결과.

DBMS는 매우 자주 동일하거나 유사한 요청이 오는 것을 확인합니다. 그런 다음 단순히 이러한 요청과 해당 응답을 캐싱하기 시작합니다. 그러나 동시에 데이터베이스에서 변경된 행이 적시에 캐시에서 제거되었는지 확인해야 합니다.

이 접근 방식은 쿼리를 분석하고 DBMS가 쿼리를 가장 잘 캐시하는 방법을 파악하는 데 도움을 줄 수 있는 사람에게 매우 효과적일 수 있습니다.

세 번째 접근 방식은 메모리 내 데이터베이스 입니다 .

일반적으로 사용되는 또 다른 접근 방식입니다. 또 다른 데이터베이스는 서버와 DBMS 사이에 배치되어 모든 데이터를 메모리에만 저장합니다. In-Memory-DB라고도 합니다. 동일한 데이터베이스에 액세스하는 여러 서버가 있는 경우 In-Memory-DB를 사용하여 특정 서버 유형에 따라 캐싱을 구성할 수 있습니다.

예:

접근법 4 - 데이터베이스 클러스터 . 여러 읽기 전용 베이스.

또 다른 솔루션은 클러스터를 사용하는 것입니다. 동일한 유형의 여러 DBMS에 동일한 데이터가 포함됩니다. 동시에 모든 데이터베이스에서 데이터를 읽고 한 데이터베이스에만 쓸 수 있습니다. 그런 다음 나머지 데이터베이스와 동기화됩니다.

이것은 구성하기 쉽고 실제로 작동하기 때문에 매우 좋은 솔루션입니다. 일반적으로 데이터베이스에 대한 데이터 변경 요청 한 건에 대해 데이터 읽기 요청이 10-100건 발생합니다.

Hibernate의 캐싱 유형

Hibernate는 세 가지 수준의 캐싱을 지원합니다.

  • 세션 수준에서 캐싱(세션)
  • SessionFactory 수준에서 캐싱
  • 캐싱 요청(및 그 결과)

이러한 그림의 형태로 이 시스템을 나타낼 수 있습니다.

가장 간단한 유형의 캐싱( 첫 번째 수준 캐시 라고도 함 )은 Hibernate 세션 수준에서 구현됩니다. Hibernate는 기본적으로 항상 이 캐시를 사용하며 비활성화할 수 없습니다 .

다음 예를 즉시 살펴보겠습니다.

Employee director1 = session.get(Employee.class, 4);
Employee director2 = session.get(Employee.class, 4);

assertTrue(director1 == director2);

여기에서 데이터베이스에 대한 두 개의 쿼리가 실행되는 것처럼 보일 수 있지만 그렇지 않습니다. 데이터베이스에 대한 첫 번째 요청 후 직원 개체가 캐시됩니다. 그리고 동일한 세션에서 객체를 다시 쿼리하면 Hibernate는 동일한 Java 객체를 반환합니다.

동일한 개체는 개체 참조도 동일함을 의미합니다. 정말 같은 개체입니다.

save() , update() , saveOrUpdate() , load() , get() , list() , iterate()scroll() 메서드는 항상 첫 번째 수준 캐시를 사용합니다. 사실 더 추가할 것은 없습니다.

2단계 캐싱

첫 번째 수준 캐시가 세션 개체에 바인딩된 경우 두 번째 수준 캐시는 세션 개체에 바인딩됩니다.세션팩토리. 즉, 이 캐시에 있는 개체의 가시성이 첫 번째 수준 캐시보다 훨씬 넓습니다.

예:

Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();

Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();

assertTrue(director1 != director2);
assertTrue(director1.equals(director2));

이 예에서는 데이터베이스에 대해 두 개의 쿼리가 작성됩니다. Hibernate는 동일한 객체를 반환하지만 동일한 객체가 아닐 것입니다. 서로 다른 참조를 가질 것입니다.

2단계 캐싱은 기본적으로 비활성화되어 있습니다 . 따라서 하나가 아닌 두 개의 데이터베이스 쿼리가 있습니다.

이를 활성화하려면 hibernate.cfg.xml 파일에 다음 줄을 작성해야 합니다.

<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletEhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>

2단계 캐싱을 활성화한 후 Hibernate 동작이 약간 변경됩니다.

Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();

Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();

assertTrue(director1 == director2);

이러한 모든 조작 후에야 두 번째 수준 캐시가 활성화되고 위의 예에서는 데이터베이스에 대한 쿼리가 하나만 실행됩니다.