@Transactional 적용 x
<Plan> 테이블의 모습입니다.
<Plan> 테이블의 PLAN_ID가 1인 행의 데이터를 update 하려고 합니다.
PlanController
@ResponseBody
@PatchMapping("")
public Plan updatePlan(@RequestBody Plan plan) {
return planService.update(plan.getPlanId(), plan.getPlanTitle(), plan.getBudget(), plan.getPlanStartDate(), plan.getPlanEndDate());
}
먼저 @PatchMapping을 사용해 업데이트 요청을 받을 Controller를 작성합니다.
PlanService
@Service
@RequiredArgsConstructor
public class PlanService {
private final PlanRepository planRepository;
// @Transactional
public Plan update(Long planId, String planTitle, int budget, LocalDateTime planStartDate, LocalDateTime planEndDate) {
return planRepository.update(planId, planTitle, budget, planStartDate, planEndDate);
}
}
Service에서는 PlanRepository의 update() 메서드를 여러 데이터를 넘기며 호출합니다
이때 @Transaction은 주석처리 한 상태로 해보겠습니다.
PlanRepository
@Repository
@RequiredArgsConstructor
public class PlanRepository{
private final EntityManager em;
public Plan update(Long planId, String planTitle, int budget, LocalDateTime planStartDate, LocalDateTime planEndDate) {
Plan plan = em.find(Plan.class, planId);
plan.setPlanTitle(planTitle);
plan.setBudget(budget);
plan.setPlanStartDate(planStartDate);
plan.setPlanEndDate(planEndDate);
return plan;
}
}
PlanRepository에서 EntityManger를 사용해서 데이터를 업데이트합니다.
update()함수는 파라미터로 넘어온 planId로 해당 행을 찾아서 각 데이터를 setXXX 처리하고
그 필드가 변경된 Plan 인스턴스를 반환합니다.
업데이트가 되는지 PostMan으로 Patch 요청을 보냅니다.
planTitle만 "changedTitle"로 변경해보겠습니다.
<Plan> 테이블을 다시 확인해보니
PLAN_ID가 1인 행의 PLAN_TITLE이 'title'로 유지하고 있습니다.
@Transactional 적용
PlanService
@Transactional
public Plan update(Long planId, String planTitle, int budget, LocalDateTime planStartDate, LocalDateTime planEndDate) {
return planRepository.update(planId, planTitle, budget, planStartDate, planEndDate);
}
PlanService의 update() 메서드에 @Transactional 어노테이션을 적용하고 다시 Patch 요청을 보내봅시다.
PLAN_ID가 1인 행의 PLAN_TITLE이 'changeTitle'로 변경된 걸 볼 수 있습니다.
테스트코드 - @Transactional 적용 x
PlanServiceTest
@Test
//@Transactional
public void 계획_수정() {
//given
Plan findPlan = planService.findById(1L);
//when
Plan changePlan = planService.update(findPlan.getPlanId(), "changedTitle", 50000,
LocalDateTime.of(2018, 10, 22, 14, 00, 00, 00),
LocalDateTime.of(2020, 6, 4, 13, 00, 00, 00)
);
//then
Plan findPlan2 = planService.findById(changePlan.getPlanId());
log.info(findPlan2.getPlanTitle());
Assertions.assertThat(findPlan2.getPlanTitle()).isEqualTo(changePlan.getPlanTitle());
}
테스트코드에서도 @Tranactional을 주석처리하고 실행해보겠습니다.
findById()를 통해 얻은 제목을"changedTitle"로 예상했지만 결과는 바뀌지 않은 "title"로 유지되어 테스트에 실패합니다.
테스트코드 - @Transactional 적용 x
PlanServiceTest
@Test
@Transactional
public void 계획_수정() {
//given
Plan findPlan = planService.findById(1L);
//when
Plan changePlan = planService.update(findPlan.getPlanId(), "changedTitle", 50000,
LocalDateTime.of(2018, 10, 22, 14, 00, 00, 00),
LocalDateTime.of(2020, 6, 4, 13, 00, 00, 00)
);
//then
Plan findPlan2 = planService.findById(changePlan.getPlanId());
log.info(findPlan2.getPlanTitle());
Assertions.assertThat(findPlan2.getPlanTitle()).isEqualTo(changePlan.getPlanTitle());
}
이번엔 @Tranactional 활성화하고 다시 테스트를 실행해보면
테스트가 정상적으로 성공했습니다.
왜 @Transactional를 해야하나?
JPA에서는 @Transactional 어노테이션을 통해 트랜잭션을 관리합니다.
트랜잭션이 시작되면 엔티티 매니저는 해당 트랜잭션 범위 내에서 엔티티의 변경 사항을 추적하고,
트랜잭션이 커밋될 때 변경 사항을 데이터베이스에 반영합니다.
@Transactional이 없으면 엔티티의 변경 사항이 영속성 컨텍스트에 반영되지 않으며,
데이터베이스에 변경 사항이 저장되지 않습니다.
@Transactional 어노테이션을 사용해 트랜잭션 범위 내에서 엔티티를 수정하고 이를 커밋해야만 변경 사항이 데이터베이스에 반영됩니다.
'Spring' 카테고리의 다른 글
[tomcat] 톰캣 로그 한글 깨짐 (0) | 2024.07.23 |
---|---|
[tomcat] error running tomcat can't find catalina.jar (1) | 2024.07.23 |
[SpringBoot] DI 생성자 주입 (1) | 2023.10.26 |
[SpringBoot] 프로젝트 빌드 및 실행 (0) | 2023.10.17 |
[SpringBoot/Thymeleaf] ajax 회원가입 중복체크 2 (0) | 2022.06.28 |