커넥션 풀링 및 캐싱
이전 튜토리얼에서는 Exposed 프레임워크를 사용하여 웹사이트에 영속성(persistence)을 추가했습니다. 이 튜토리얼에서는 HikariCP 및 Ehcache 라이브러리를 각각 사용하여 데이터베이스 커넥션 풀링과 캐싱을 구현하는 방법을 살펴보겠습니다.
의존성 추가
먼저, HikariCP 및 Ehcache 라이브러리에 대한 의존성을 추가해야 합니다. gradle.properties 파일을 열고 라이브러리 버전을 지정합니다:
h2_version = 2.3.232
hikaricp_version = 5.1.0그런 다음, build.gradle.kts를 열고 다음 의존성들을 추가합니다:
build.gradle.kts 파일의 오른쪽 상단에 있는 Load Gradle Changes 아이콘을 클릭하여 새로 추가된 의존성들을 설치합니다.
커넥션 풀링
Exposed는 transaction 범위 내에서 데이터베이스에 대한 첫 번째 조작을 수행할 때 각 transaction 호출 내부에서 새로운 JDBC 커넥션을 시작합니다. 하지만 여러 JDBC 커넥션을 생성하는 것은 리소스 비용이 많이 듭니다. 기존 커넥션을 재사용하면 성능을 개선하는 데 도움이 될 수 있습니다. 커넥션 풀링(connection pooling) 메커니즘이 이 문제를 해결합니다.
이 섹션에서는 애플리케이션에서 JDBC 커넥션 풀링을 관리하기 위해 HikariCP 프레임워크를 사용합니다.
설정 파일로 연결 설정 추출하기
이전 튜토리얼에서는 데이터베이스 연결을 설정하기 위해 com/example/dao/DatabaseSingleton.kt 파일에 driverClassName과 jdbcURL을 하드코딩했습니다:
데이터베이스 연결 설정을 사용자 정의 구성 그룹으로 추출해 보겠습니다.
src/main/resources/application.conf파일을 열고ktor그룹 외부에 다음과 같이storage그룹을 추가합니다:kotlincom/example/dao/DatabaseSingleton.kt를 열고 구성 파일에서 스토리지 설정을 로드하도록init함수를 업데이트합니다:kotlin이제
init함수는ApplicationConfig를 받아들이고config.property를 사용하여 사용자 정의 설정을 로드합니다.마지막으로,
com/example/Application.kt를 열고 애플리케이션 시작 시 연결 설정을 로드하도록environment.config를DatabaseSingleton.init에 전달합니다:kotlin
커넥션 풀링 활성화하기
Exposed에서 커넥션 풀링을 활성화하려면 DataSource를 Database.connect 함수의 파라미터로 제공해야 합니다. HikariCP는 DataSource 인터페이스를 구현하는 HikariDataSource 클래스를 제공합니다.
HikariDataSource를 생성하기 위해com/example/dao/DatabaseSingleton.kt를 열고DatabaseSingleton객체에createHikariDataSource함수를 추가합니다:kotlin데이터 소스 설정에 대한 몇 가지 참고 사항은 다음과 같습니다:
createHikariDataSource함수는 드라이버 클래스 이름과 데이터베이스 URL을 파라미터로 받습니다.maximumPoolSize속성은 커넥션 풀이 도달할 수 있는 최대 크기를 지정합니다.isAutoCommit및transactionIsolation은 Exposed에서 사용하는 기본 설정과 동기화되도록 설정됩니다.
HikariDataSource를 사용하려면 이를Database.connect함수에 전달합니다:kotlin이제 애플리케이션을 실행하여 모든 것이 이전과 같이 작동하는지 확인할 수 있습니다.
캐싱
데이터베이스에 데이터베이스 캐시를 보충할 수 있습니다. 캐싱은 자주 사용되는 데이터를 임시 메모리에 저장하는 기술로, 데이터베이스의 부하를 줄이고 자주 필요한 데이터를 읽는 시간을 단축할 수 있습니다.
이 튜토리얼에서는 Ehcache 라이브러리를 사용하여 파일에 캐시를 구성합니다.
설정에 캐시 파일 경로 추가하기
src/main/resources/application.conf 파일을 열고 storage 그룹에 ehcacheFilePath 속성을 추가합니다:
이 속성은 캐시 데이터를 저장하는 데 사용되는 파일의 경로를 지정합니다. 나중에 캐시 작업을 위한 DAOFacade 구현을 구성할 때 이 속성을 사용합니다.
캐싱 구현하기
캐싱을 구현하려면 캐시에서 값을 반환하고, 캐시된 값이 없는 경우 데이터베이스 인터페이스로 위임하는 또 다른 DAOFacade 구현을 제공해야 합니다.
com.example.dao패키지에 새로운DAOFacadeCacheImpl.kt파일을 생성하고 다음 구현을 추가합니다:kotlin이 코드 샘플의 간략한 개요는 다음과 같습니다:
- 캐시를 초기화하고 구성하기 위해 Ehcache
CacheManager인스턴스를 정의합니다. 디스크 저장소로 사용할 루트 디렉토리로storagePath를 제공합니다. - ID별로 기사(article)를 저장하는 항목에 대한 캐시를 생성합니다.
articlesCache는Int키를Article값에 매핑합니다. - 그런 다음 로컬 메모리 및 디스크 리소스에 대한 크기 제한을 제공합니다. 이러한 파라미터에 대한 자세한 내용은 Ehcache 문서에서 확인할 수 있습니다.
- 마지막으로, 제공된 이름, 키 및 값 타입을 사용하여
cacheManager.getCache()를 호출함으로써 생성된 캐시를 가져옵니다.
- 캐시를 초기화하고 구성하기 위해 Ehcache
캐시에서 사용되려면
Article클래스는 직렬화 가능해야 하며java.io.Serializable을 구현해야 합니다.com/example/models/Article.kt를 열고 코드를 다음과 같이 업데이트합니다:kotlin이제
DAOFacade의 멤버들을 구현할 준비가 되었습니다.DAOFacadeCacheImpl.kt로 돌아가서 다음 메서드들을 추가합니다:kotlinallArticles: 모든 기사를 캐싱하려고 시도하지 않고, 메인 데이터베이스에 위임합니다.article: 기사를 가져올 때 먼저 캐시에 있는지 확인하고, 없는 경우에만 메인DAOFacade에 위임하고 해당 기사를 캐시에 추가합니다.addNewArticle: 새 기사를 추가할 때 메인DAOFacade에 위임하지만, 해당 기사를 캐시에도 추가합니다.editArticle: 기존 기사를 수정할 때 캐시와 데이터베이스를 모두 업데이트합니다.deleteArticle: 삭제 시 캐시와 메인 데이터베이스 모두에서 기사를 삭제해야 합니다.
DAOFacadeCacheImpl 초기화하기
DAOFacadeCacheImpl 인스턴스를 생성하고, 애플리케이션이 시작되기 전에 데이터베이스에 삽입될 샘플 기사를 추가해 보겠습니다:
먼저,
DAOFacadeImpl.kt파일을 열고 파일 하단의dao변수 초기화 코드를 제거합니다.그런 다음,
com/example/plugins/Routing.kt를 열고configureRouting블록 내부에서dao변수를 초기화합니다:kotlin이제 끝났습니다. 이제 애플리케이션을 실행하여 모든 것이 이전과 같이 작동하는지 확인할 수 있습니다.
커넥션 풀링 및 캐싱이 포함된 전체 예제는 여기에서 찾을 수 있습니다: tutorial-website-interactive-persistence-advanced.
