회원, 상품 도메인 개발

기석·2022년 5월 14일
0
post-thumbnail

출처: 실전 스프링 부트와 JPA 활용1, 영속성 컨텍스트란

애플리케이션 아키텍쳐

구현 순서
1. 서비스, 리포지토리 계층 개발
2. 테스트 케이스 작성 및 검증
3. 웹 계층 적용


EntityManager, EntityManagerFactory

선언할 때 @PersistenceContext를 이용한다. 영속성 컨텍스트라 한다.

EntityManager

  • 내부적으로 DB Connection pool을 사용해서 DB에 접근한다.
  • 실제 Transaction 단위를 수행할 때마다 생성한다.
  • 즉 고객의 요청이 올 때마다 사용했다가 닫는다.
  • thread간 공유를 하면 안된다.
  • Transaction 수행 후에는 반드시 EntityManger를 닫아야 내부적으로 DB Connection을 반환한다.

EntityManagerFactory

  • 고객의 요청이 올 때마다 EntityManager를 생성한다.
  • Application Loading 시점에 DB 당 딱 하나만 생성되어야 한다.
  • WAS가 종료되는 시점에 EntityManagerFactory를 닫는다.
  • 그래야 내부적으로 Connection Pooling에 대한 Resource 가 Release 된다.

영속성 컨텍스트 (Persistence Context)

  • Entity를 영구 저장하는 환경이라는 뜻이다.
  • JPA를 이해하는데 가장 중요한 용어.
  • 논리적인 개념.
  • entityManager.persist(entity) 는
    내부적으로 실제 DB에 저장하는 것이 아니고 영속성 컨텍스트를 통해서 Entity를 영속화 한다는 뜻이다.
  • EntityManager가 생성되면 1:1로 영속성 컨텍스트가 생성되며,
    EntityManager를 통해서 영속성 컨텍스트에 접근할 수 있다.

엔티티의 생명주기

  • 비영속: 객체를 생성만하고 영속성 컨텍스트와는 관계가 없는 상태.
  • 영속: 영속성 컨텍스트에 저장된 상태. Entity가 영속성 컨텍스트에 의해 관리된다.
    ( em.persist(member) )
  • 준영속: 영속성 컨텍스트에 저장되었다가 분리된 상태. ( em.detach(member) )
  • 삭제: 실제 DB에서 삭레를 요청한 상태 ( em.remove(member )

나머지 영속성 컨텍스트에 대한 내용들은 영속성 컨텍스트란에 상세히 나와있어서
많은 도움이 되었다.


서비스, 리포지토리를 구현하는 것은 스프링 강의에서 몇 번 해봤던 것처럼 하면 어렵지 않다.
스프링 강의 외 이번 강의에서 새로 알게된 것들만 몇가지 정리하겠다.

@Repository
public class MemberRepository {
	@PersistenceContext
	private EntityManager em;

@Repository
@RequiredArgsConstructor
public class MemberRepository {
	private final EntityManager em;

와 같이도 쓸 수 있다. 스프링 데이터 JPA를 사용하면 가능하다.

테스트 코드

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class MemberServiceTest {

위 어노테이션들을 붙여주어야 정상적으로 JPA를 사용할 수 있다.

테스트케이스를 위한 설정

  • test/resources/application.yml
    이렇게 만들면 테스트 전용 application.yml 설정 값들이 적용된다.

테스트를 격리된 환경에서 실행하고 검증 후 데이터 초기화를 하기 위해 메모리 DB를 사용하는 것이 이상적이다.

spring:
# datasource:
# url: jdbc:h2:mem:testdb
# username: sa
# password:
# driver-class-name: org.h2.Driver
# jpa:
# hibernate:
# ddl-auto: create
# properties:
# hibernate:
 # show_sql: true
# format_sql: true
# open-in-view: false
logging.level:
 org.hibernate.SQL: debug
# org.hibernate.type: trace

스프링 부트는 datasource 설정 파일이 없으면 자동으로 메모리 DB를 사용하기 때문에
없어도 되는 부분을 주석처리 하였다.

addStock(), removeStock()

  • 상품 서비스에서 상품 엔티티의 stock을 컨트롤 하기보다는,
  • 상품 엔티티에 비즈니스 로직을 만드는 것이 엔티티의 독립성을 지켜주기 좋다.

@Transactional(readonly=true)

@Service
@Transactional(readOnly = true)
public class MemberService {
	@Autowired
	MemberRepository memberRepository;
	/**
	* 회원가입
	*/
	@Transactional //변경
	public Long join(Member member) {
		validateDuplicateMember(member); //중복 회원 검증
		memberRepository.save(member);
		return member.getId();
	}
    ...

readonly=true 옵션을 주면 최적화에 좋다.
클래스에 일괄적으로 적용한 후, DB 쓰기를 하는 메서드만 따로 @Transactional을 주면 편하다.
참고로 @Transactional은 readonly=false을 기본 값으로 가지고 있다.

profile
개바라자

0개의 댓글