From b319fd0dc86c6a92e1a842b83cd21425c8ecb8ae Mon Sep 17 00:00:00 2001 From: belljun3395 <195850@jnu.ac.kr> Date: Sun, 28 Jul 2024 23:24:06 +0900 Subject: [PATCH] =?UTF-8?q?[Feat/#238]=20=EC=9B=8C=ED=81=AC=EB=B6=81=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B2=A0=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=BC=80=EC=8B=9C=20=EC=84=A4=EC=A0=95=20(#246)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: SELECT_WORKBOOK_RECORD_CACHE 추가 * refactor: selectWorkBook 메서드 데이터 베이스 케시 설정 * feat: WorkBookCacheManager 구현 * feat: SELECT_WRITER_CACHE 추가 * feat: MemberCacheManager 구현 * feat: MemberCacheManager 적용 * refactor: 동시성을 고려한 수정 * refactor: 캐시 사이즈 수정 * refactor: 변수 이름 수정 * refactor: 복수형 이름으로 수정 --- .../few/api/repo/config/LocalCacheConfig.kt | 25 ++++++++++-- .../api/repo/dao/member/MemberCacheManager.kt | 40 +++++++++++++++++++ .../com/few/api/repo/dao/member/MemberDao.kt | 29 ++++++++++++-- .../repo/dao/workbook/WorkBookCacheManager.kt | 24 +++++++++++ .../few/api/repo/dao/workbook/WorkbookDao.kt | 4 ++ 5 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberCacheManager.kt create mode 100644 api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkBookCacheManager.kt diff --git a/api-repo/src/main/kotlin/com/few/api/repo/config/LocalCacheConfig.kt b/api-repo/src/main/kotlin/com/few/api/repo/config/LocalCacheConfig.kt index 05179bfb2..9ee3a86ee 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/config/LocalCacheConfig.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/config/LocalCacheConfig.kt @@ -23,6 +23,8 @@ class LocalCacheConfig { companion object { const val LOCAL_CM = "localCacheManager" const val SELECT_ARTICLE_RECORD_CACHE = "selectArticleRecordCache" + const val SELECT_WORKBOOK_RECORD_CACHE = "selectWorkBookRecordCache" + const val SELECT_WRITER_CACHE = "selectWritersCache" } @Bean(LOCAL_CM) @@ -38,19 +40,36 @@ class LocalCacheConfig { ) val cacheManager = EhcacheCachingProvider().cacheManager - val cacheConfigurationBuilder = CacheConfigurationBuilder.newCacheConfigurationBuilder( + val cache10Configuration = CacheConfigurationBuilder.newCacheConfigurationBuilder( Any::class.java, Any::class.java, ResourcePoolsBuilder.newResourcePoolsBuilder() - .heap(50, EntryUnit.ENTRIES) + .heap(10, EntryUnit.ENTRIES) + ) + .withService(cacheEventListenerConfigurationConfig) + .build() + + val cache5Configuration = CacheConfigurationBuilder.newCacheConfigurationBuilder( + Any::class.java, + Any::class.java, + ResourcePoolsBuilder.newResourcePoolsBuilder() + .heap(5, EntryUnit.ENTRIES) ) .withService(cacheEventListenerConfigurationConfig) .build() val selectArticleRecordCacheConfig: javax.cache.configuration.Configuration = - Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfigurationBuilder) + Eh107Configuration.fromEhcacheCacheConfiguration(cache10Configuration) + val selectWorkBookRecordCacheConfig: javax.cache.configuration.Configuration = + Eh107Configuration.fromEhcacheCacheConfiguration(cache10Configuration) + + val selectWriterCacheConfig: javax.cache.configuration.Configuration = + Eh107Configuration.fromEhcacheCacheConfiguration(cache5Configuration) + runCatching { cacheManager.createCache(SELECT_ARTICLE_RECORD_CACHE, selectArticleRecordCacheConfig) + cacheManager.createCache(SELECT_WORKBOOK_RECORD_CACHE, selectWorkBookRecordCacheConfig) + cacheManager.createCache(SELECT_WRITER_CACHE, selectWriterCacheConfig) }.onFailure { log.error(it) { "Failed to create cache" } } diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberCacheManager.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberCacheManager.kt new file mode 100644 index 000000000..fd5dcc93a --- /dev/null +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberCacheManager.kt @@ -0,0 +1,40 @@ +package com.few.api.repo.dao.member + +import com.few.api.repo.config.LocalCacheConfig.Companion.SELECT_WRITER_CACHE +import com.few.api.repo.dao.member.record.WriterRecord +import org.springframework.cache.CacheManager +import org.springframework.stereotype.Service +import javax.cache.Cache + +@Suppress("UNCHECKED_CAST") +@Service +class MemberCacheManager( + private val cacheManager: CacheManager, +) { + + private var selectWriterCache: Cache = cacheManager.getCache(SELECT_WRITER_CACHE)?.nativeCache as Cache + + fun getAllWriterValues(): List { + val values = mutableListOf() + selectWriterCache.iterator().forEach { + values.add(it.value as WriterRecord) + } + return values + } + + fun getAllWriterValues(keys: List): List { + val values = mutableListOf() + keys.forEach { + selectWriterCache.get(it)?.let { value -> + values.add(value as WriterRecord) + } + } + return values + } + + fun addSelectWorkBookCache(records: List) { + records.forEach { + selectWriterCache.put(it.writerId, it) + } + } +} \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberDao.kt index 311722798..bddf87640 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberDao.kt @@ -1,5 +1,7 @@ package com.few.api.repo.dao.member +import com.few.api.repo.config.LocalCacheConfig.Companion.LOCAL_CM +import com.few.api.repo.config.LocalCacheConfig.Companion.SELECT_WRITER_CACHE import com.few.api.repo.dao.member.command.InsertMemberCommand import com.few.api.repo.dao.member.query.SelectMemberByEmailQuery import com.few.api.repo.dao.member.query.SelectWriterQuery @@ -10,13 +12,16 @@ import com.few.data.common.code.MemberType import jooq.jooq_dsl.tables.Member import org.jooq.DSLContext import org.jooq.impl.DSL +import org.springframework.cache.annotation.Cacheable import org.springframework.stereotype.Repository @Repository class MemberDao( private val dslContext: DSLContext, + private val cacheManager: MemberCacheManager, ) { + @Cacheable(key = "#query.writerId", cacheManager = LOCAL_CM, cacheNames = [SELECT_WRITER_CACHE]) fun selectWriter(query: SelectWriterQuery): WriterRecord? { val writerId = query.writerId @@ -32,18 +37,34 @@ class MemberDao( .fetchOneInto(WriterRecord::class.java) } + /** + * 작가 목록 조회 쿼리 + * query의 writerIds에 해당하는 작가 목록을 조회한다. + * 이때 먼저 cache에 작가 정보가 있는지 확인하고 없는 경우에만 DB에서 조회한다. + * 조회 이후에는 cache에 저장한다. + */ fun selectWriters(query: SelectWritersQuery): List { - return dslContext.select( + val cachedValues = cacheManager.getAllWriterValues().filter { it.writerId in query.writerIds } + val cachedIdS = cachedValues.map { it.writerId } + val notCachedIds = query.writerIds.filter { it !in cachedIdS } + + val fetchedValue = dslContext.select( Member.MEMBER.ID.`as`(WriterRecord::writerId.name), - DSL.jsonGetAttributeAsText(Member.MEMBER.DESCRIPTION, "name").`as`(WriterRecord::name.name), + DSL.jsonGetAttributeAsText(Member.MEMBER.DESCRIPTION, "name") + .`as`(WriterRecord::name.name), DSL.jsonGetAttribute(Member.MEMBER.DESCRIPTION, "url").`as`(WriterRecord::url.name) ) .from(Member.MEMBER) - .where(Member.MEMBER.ID.`in`(query.writerIds)) + .where(Member.MEMBER.ID.`in`(notCachedIds)) .and(Member.MEMBER.TYPE_CD.eq(MemberType.WRITER.code)) .and(Member.MEMBER.DELETED_AT.isNull) .orderBy(Member.MEMBER.ID.asc()) - .fetchInto(WriterRecord::class.java) + .fetchInto(WriterRecord::class.java).let { + cacheManager.addSelectWorkBookCache(it) + return@let it + } + + return cachedValues + fetchedValue } fun selectMemberByEmail(query: SelectMemberByEmailQuery): MemberIdRecord? { diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkBookCacheManager.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkBookCacheManager.kt new file mode 100644 index 000000000..603423dd4 --- /dev/null +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkBookCacheManager.kt @@ -0,0 +1,24 @@ +package com.few.api.repo.dao.workbook + +import com.few.api.repo.config.LocalCacheConfig.Companion.SELECT_WORKBOOK_RECORD_CACHE +import com.few.api.repo.dao.workbook.record.SelectWorkBookRecord +import org.springframework.cache.CacheManager +import org.springframework.stereotype.Service +import javax.cache.Cache + +@Suppress("UNCHECKED_CAST") +@Service +class WorkBookCacheManager( + private val cacheManager: CacheManager, +) { + + private var selectWorkBookCache: Cache = cacheManager.getCache(SELECT_WORKBOOK_RECORD_CACHE)?.nativeCache as Cache + + fun getAllSelectWorkBookValues(): List { + val values = mutableListOf() + selectWorkBookCache.iterator().forEach { + values.add(it.value as SelectWorkBookRecord) + } + return values + } +} \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkbookDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkbookDao.kt index 7efdbb5cc..a27ab95db 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkbookDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkbookDao.kt @@ -1,5 +1,7 @@ package com.few.api.repo.dao.workbook +import com.few.api.repo.config.LocalCacheConfig +import com.few.api.repo.config.LocalCacheConfig.Companion.LOCAL_CM import com.few.api.repo.dao.workbook.command.InsertWorkBookCommand import com.few.api.repo.dao.workbook.command.MapWorkBookToArticleCommand import com.few.api.repo.dao.workbook.query.SelectWorkBookRecordQuery @@ -8,12 +10,14 @@ import com.few.data.common.code.CategoryType import jooq.jooq_dsl.tables.MappingWorkbookArticle import jooq.jooq_dsl.tables.Workbook import org.jooq.DSLContext +import org.springframework.cache.annotation.Cacheable import org.springframework.stereotype.Repository @Repository class WorkbookDao( private val dslContext: DSLContext, ) { + @Cacheable(key = "#query.id", cacheManager = LOCAL_CM, cacheNames = [LocalCacheConfig.SELECT_WORKBOOK_RECORD_CACHE]) fun selectWorkBook(query: SelectWorkBookRecordQuery): SelectWorkBookRecord? { return dslContext.select( Workbook.WORKBOOK.ID.`as`(SelectWorkBookRecord::id.name),