Skip to content

Commit 627b78a

Browse files
authored
Merge pull request #2188 from BCSDLab/hotfix/2187-keyword-transaction-fix
hotfix: 키워드 알림 이력 저장 트랜잭션 분리
2 parents e41a0cf + 9f3f04a commit 627b78a

3 files changed

Lines changed: 21 additions & 4 deletions

File tree

src/main/java/in/koreatech/koin/domain/community/keyword/repository/UserNotificationStatusRepository.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ List<Integer> findUserIdsByNotifiedArticleIdAndUserIdIn(
3232

3333
@Modifying(flushAutomatically = true, clearAutomatically = true)
3434
@Query(value = """
35-
INSERT INTO user_notification_status (user_id, last_notified_article_id)
36-
VALUES (:userId, :notifiedArticleId)
37-
ON DUPLICATE KEY UPDATE last_notified_article_id = :notifiedArticleId
35+
INSERT INTO user_notification_status (user_id, last_notified_article_id, created_at, updated_at)
36+
VALUES (:userId, :notifiedArticleId, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
37+
ON DUPLICATE KEY UPDATE
38+
last_notified_article_id = :notifiedArticleId,
39+
updated_at = CURRENT_TIMESTAMP
3840
""", nativeQuery = true)
3941
void upsertLastNotifiedArticleId(
4042
@Param("userId") Integer userId,

src/main/java/in/koreatech/koin/domain/community/keyword/service/KeywordService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.springframework.data.domain.PageRequest;
1010
import org.springframework.data.domain.Pageable;
1111
import org.springframework.stereotype.Service;
12+
import org.springframework.transaction.annotation.Propagation;
1213
import org.springframework.transaction.annotation.Transactional;
1314

1415
import in.koreatech.koin.domain.community.article.exception.ArticleNotFoundException;
@@ -206,7 +207,7 @@ public void fetchTopKeywordsFromLastWeek() {
206207
}
207208
}
208209

209-
@Transactional
210+
@Transactional(propagation = Propagation.REQUIRES_NEW)
210211
public void createNotifiedArticleStatus(Integer userId, Integer articleId) {
211212
userNotificationStatusRepository.upsertLastNotifiedArticleId(userId, articleId);
212213
}

src/test/java/in/koreatech/koin/unit/domain/community/keyword/service/KeywordServiceTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package in.koreatech.koin.unit.domain.community.keyword.service;
22

3+
import static org.assertj.core.api.Assertions.assertThat;
34
import static org.mockito.Mockito.mock;
45
import static org.mockito.Mockito.verify;
56
import static org.mockito.Mockito.verifyNoInteractions;
67
import static org.mockito.Mockito.verifyNoMoreInteractions;
78
import static org.mockito.Mockito.when;
89

10+
import java.lang.reflect.Method;
911
import java.util.List;
1012
import java.util.Map;
1113

@@ -16,6 +18,8 @@
1618
import org.mockito.Mock;
1719
import org.mockito.junit.jupiter.MockitoExtension;
1820
import org.springframework.context.ApplicationEventPublisher;
21+
import org.springframework.transaction.annotation.Propagation;
22+
import org.springframework.transaction.annotation.Transactional;
1923

2024
import in.koreatech.koin.common.event.ArticleKeywordEvent;
2125
import in.koreatech.koin.domain.community.article.model.Article;
@@ -107,4 +111,14 @@ void createNotifiedArticleStatus_usesAtomicUpsert() {
107111

108112
verify(userNotificationStatusRepository).upsertLastNotifiedArticleId(1, 100);
109113
}
114+
115+
@Test
116+
@DisplayName("발송 이력 저장은 항상 새로운 트랜잭션에서 수행한다.")
117+
void createNotifiedArticleStatus_startsNewTransaction() throws NoSuchMethodException {
118+
Method method = KeywordService.class.getMethod("createNotifiedArticleStatus", Integer.class, Integer.class);
119+
Transactional transactional = method.getAnnotation(Transactional.class);
120+
121+
assertThat(transactional).isNotNull();
122+
assertThat(transactional.propagation()).isEqualTo(Propagation.REQUIRES_NEW);
123+
}
110124
}

0 commit comments

Comments
 (0)