Skip to content

Commit b54a9e5

Browse files
authored
Merge pull request #2127 from BCSDLab/fix/abtest-left-inner-join
hotfix: accessHistory 조회 실패 해결
2 parents 21d4c77 + e0dbf5e commit b54a9e5

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

src/main/java/in/koreatech/koin/admin/abtest/repository/AccessHistoryRepository.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ public interface AccessHistoryRepository extends Repository<AccessHistory, Integ
1919

2020
@Lock(LockModeType.PESSIMISTIC_WRITE)
2121
@QueryHints({@QueryHint(name = "jakarta.persistence.lock.timeout", value = "3000")})
22-
@Query("SELECT a FROM AccessHistory a JOIN FETCH a.device WHERE a.id = :id")
22+
@Query("SELECT a FROM AccessHistory a LEFT JOIN FETCH a.device WHERE a.id = :id")
2323
Optional<AccessHistory> findById(Integer id);
2424

2525
@Lock(LockModeType.PESSIMISTIC_WRITE)
2626
@QueryHints({@QueryHint(name = "jakarta.persistence.lock.timeout", value = "3000")})
27-
@Query("SELECT a FROM AccessHistory a JOIN FETCH a.device WHERE a.device.id = :deviceId")
27+
@Query("SELECT a FROM AccessHistory a LEFT JOIN FETCH a.device WHERE a.device.id = :deviceId")
2828
Optional<AccessHistory> findByDeviceId(@Param("deviceId") Integer deviceId);
2929

3030
default AccessHistory getById(Integer accessHistoryId) {

src/test/java/in/koreatech/koin/acceptance/domain/AbtestApiTest.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
import static org.assertj.core.api.Assertions.assertThat;
44
import static org.assertj.core.api.SoftAssertions.assertSoftly;
55
import static org.junit.jupiter.api.Assertions.assertNotEquals;
6-
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
6+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
7+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
8+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
9+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
710
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
811
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
912

1013
import java.util.Optional;
1114

1215
import org.junit.jupiter.api.BeforeAll;
16+
import org.junit.jupiter.api.DisplayName;
1317
import org.junit.jupiter.api.Test;
1418
import org.springframework.beans.factory.annotation.Autowired;
1519
import org.springframework.http.MediaType;
@@ -23,14 +27,18 @@
2327
import in.koreatech.koin.acceptance.fixture.UserAcceptanceFixture;
2428
import in.koreatech.koin.admin.abtest.model.Abtest;
2529
import in.koreatech.koin.admin.abtest.model.AbtestVariable;
30+
import in.koreatech.koin.admin.abtest.model.AccessHistory;
2631
import in.koreatech.koin.admin.abtest.model.AccessHistoryAbtestVariable;
2732
import in.koreatech.koin.admin.abtest.model.Device;
2833
import in.koreatech.koin.admin.abtest.repository.AbtestRepository;
34+
import in.koreatech.koin.admin.abtest.repository.AccessHistoryRepository;
2935
import in.koreatech.koin.admin.abtest.repository.DeviceRepository;
3036
import in.koreatech.koin.admin.manager.model.Admin;
3137
import in.koreatech.koin.domain.owner.model.Owner;
3238
import in.koreatech.koin.domain.student.model.Department;
3339
import in.koreatech.koin.domain.student.model.Student;
40+
import jakarta.persistence.EntityManager;
41+
import jakarta.persistence.PersistenceContext;
3442

3543
class AbtestApiTest extends AcceptanceTest {
3644

@@ -55,6 +63,12 @@ class AbtestApiTest extends AcceptanceTest {
5563
@Autowired
5664
private DepartmentAcceptanceFixture departmentFixture;
5765

66+
@Autowired
67+
private AccessHistoryRepository accessHistoryRepository;
68+
69+
@PersistenceContext
70+
EntityManager em;
71+
5872
private Admin admin;
5973
private String adminToken;
6074
private Department department;
@@ -549,4 +563,26 @@ void setUp() {
549563
String responseBody2 = mvcResult2.getResponse().getContentAsString();
550564
assertNotEquals(responseBody, responseBody2);
551565
}
566+
567+
@Test
568+
@DisplayName("디바이스가 없는 접속 이력을 조회할 때 INNER JOIN으로 인한 누락을 검증한다")
569+
void 디바이스_없는_이력_조회_테스트() {
570+
// given
571+
// 1. 디바이스가 없는 AccessHistory를 생성해서 저장합니다.
572+
AccessHistory history = AccessHistory.create();
573+
accessHistoryRepository.save(history);
574+
575+
// 2. 영속성 컨텍스트를 비워 실제 DB 쿼리가 나가도록 유도합니다.
576+
em.flush();
577+
em.clear();
578+
579+
// when
580+
Optional<AccessHistory> result = accessHistoryRepository.findById(history.getId());
581+
582+
// then
583+
// INNER JOIN -> 결과가 비어있음(실패)
584+
// LEFT JOIN -> 결과에 포함됨(성공)
585+
assertThat(result).isPresent();
586+
assertThat(result.get().getId()).isEqualTo(history.getId());
587+
}
552588
}

0 commit comments

Comments
 (0)