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),