728x90
반응형
어노테이션
- @Repository : 스프링 빈으로 등록되도록 해주고, JPA Exception을 Spring 기반 Exception으로 변환
- @Service : 비즈니스 로직을 처리하는 객체를 스프링 빈으로 등록
- @Transactional : 트랜잭션을 보내고, 트랜잭션의 성질을 기준으로 commit할 지, rollback할 지 판단해줍니다.
- readOnly = true : 데이터 변경이 없는 메서드에 사용
- 영속성 context를 flush하지 않으므로 약간의 성능 향상을 기대할 수 있음
- 기본값은 false이므로 메서드의 용도에 맞게 annotation을 정해야 함
- @RequiredArgsConstructor : Spring boot에서 final 처리된 필드를 파라미터로 갖는 생성자를 만들어줌
- 따라서 @Autowired annotation을 쓰지 않고, 생성자로 주입하는 코드 없이도 그 역할을 수행할 수 있음
- 대부분 권장하는 방법 또한 @Autowired를 통한 필드 주입보다는 생성자 주입을 권장하므로 이 방법을 사용
생성자 주입의 장점
- 의존관계 설정이 되지 않으면 객체생성 불가 -> 컴파일 타임에 인지 가능
- 의존성 주입이 필요한 필드를 final 로 선언가능 -> 불변성
- (스프링에서) 순환참조 감지가능 -> 순환참조시 앱구동 실패
- 테스트 코드 작성 용이
Flush란?
- 영속성 컨텍스트의 변경 내용을 DB 에 반영하는 것(영속성 컨텍스트를 비우는 것이 아님!)
- 영속성 컨텍스트 : 엔티티를 영구 저장하는 환경
- Transaction commit 이 일어날 때 flush가 동작하는데, 이때 쓰기 지연 저장소에 쌓아 놨던 INSERT, UPDATE, DELETE SQL들이 DB에 날라감
- 영속성 컨텍스트의 변경 사항들과 DB의 상태를 맞추는 작업
테스트 코드
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class OrderServiceTest {
@PersistenceContext
EntityManager em;
@Autowired
OrderService orderService;
/* test code */
@Test
public void 상품주문() throws Exception {}
}
- @RunWith(SpringRunner.class) : Spring과 테스트를 통합하겠다는 의미
- @SpringBootTest : 테스트 코드를 실행하기 전에 Spring Boot를 띄우고 하겠다는 의미. 없을 경우 @Autowired와 같은 annotation들은 모두 실패
- @Transactional : 각각의 테스트를 실행할 때마다 트랜잭션을 시작하고 테스트가 끝나면 강제로 rollback하여 반복 가능한 테스트를 지원
save()
- id 가 없으면 신규로 보고 persist() 실행
- id 가 있으면 이미 데이터베이스에 저장된 엔티티를 수정한다고 보고, merge() 를 실행
Update(수정) 시 save() 메서드를 호출하는 것이 좋을까?
- JPA를 사용하면 트랜잭션 범위 안에서 Dirty Checking이 동작
- save() 메서드를 호출하지 않아도 값이 알아서 수정되고 반영
@Transactional만을 사용한 예제
@Transactional
public Noticeupdate(Long noticeId, String content) {
Notice notice = noticeRepository.findById(noticeId).get();
notice.setContent(content);
}
repository.save() 메서드를 사용한 예제
public Noticeupdate(Long noticeId, String content) {
Notice notice = noticeRepository.findById(noticeId).get();
notice.setContent(content);
noticeRepository.save(notice);
}
위 두 코드의 최종 상태는 동일하다.
- 1번 코드의 경우 객체가 자기 할일만 하는 코드이고,
- 2번 코드의 경우 객체의 관점에서 자신의 상태를 변경한 후에, DB에도 따로 반영을 해주는 코드이다.
즉, 2번 코드는 외부 인프라인 DBMS를 우려한 코드이고, 객체 지향 관점에서 좋은 형태로 보긴 힘들다.
테스트 관점?
- Service 클래스에 대한 단위 테스트를 진행하기 위해서는 Repository Mocking 필요
- 서비스단에서 save() 메서드를 의미없이 호출하게 되면, 불필요하게 Mocking할 메서드가 하나 더 늘어남
- 따라서 테스트 코드가 복잡해짐
결론
- 새로운 엔터티를 추가할 때는 repository.save() 메서드 사용
- 기존 엔티티를 수정하는 작업은 사용안하는 것이 더 깔끔
728x90
반응형
'Tech > Spring' 카테고리의 다른 글
[Spring] 스프링 빈이란? 스프링 빈 정리 (등록방식, 스코프) (0) | 2023.08.01 |
---|---|
[Spring JPA] 준영속 상태, 더티 체킹, 변경감지, 병합 (0) | 2023.04.17 |
[Spring Data JPA] 스프링 테이블, 컬럼명 생성 전략 (0) | 2023.03.22 |
[Spring Data JPA] 스프링 Entity 설계 시 주의사항 (0) | 2023.03.21 |
[Spring] jasypt로 암호화하기, docker, ec2 및 CI/CD 연동하기 (0) | 2023.01.19 |