<application.yml>
* jpa:generate-ddl: jpa 구현체와 상관없이 자동화된 ddl을 사용하도록 하는 것, Spring Application 실행시점에 Hibernate에서 자동으로 DDL을 생성해서 필요한 데이터베이스의 Table설정을 자동으로 수행
* jpa:hibernate:ddl-auto : 데이터베이스의 초기화 전략
: none / create-drop(시작 할 때 생성, 종료 때 drop) / update(변경된 스키마를 적용)
/create(항상 새로 생성) / validate(변경사항이 있으면 변경사항을 출력하고 종료) 중에 값을 가짐
: 위에 generate-ddl값 과 상충하면 ddl-auto를 따름
* datasource:initialization-mode
: data.sql, 스키마파일을 불러올지 말지 결정 (sql : init : mode로 변경된듯)
: 종류=> always(모든db)/embeded(embeded디비에서만)/none(안함)
: 현업에서는 데이터 초기화를 하면 안되므로 보통 none으로 한다.
: ddl-auto와 이게 둘다 켜져있으면, 이걸 따른다. (data.sql은 데이터 주입, 스키마는 스키마생성이므로 스키마파일이 없다면 ddl-auto를 따름)
* h2는 테스트 db로써 임베디드 db이다. ddl-auto가 create-drop , initialzation-mode가 embeded이 디폴트 설정이다.
<통합테스트>
* 테스트 최상단에 @Transactional을 붙이면 각 유닛테스트에서 생성했던 데이터를 유닛테스트 끝날 때 삭제. 각 테스트끼리 영향을 미치지 않는다.
* controllerTest에서는 @WebMvcTest 때문에 슬라이스테스트가 실행된다. 이걸 개선하는 방법은 세가지가 있음 (-슬라이스테스트 : 전체 컨텍스트를 로딩하지 않고 웹컨트롤러에 대한 일부 빈들만 로딩해서 테스트, 따라서 Jpa관련한게 없음)
1) @MockBean(JpaMetamodelMappingContext.class) 를 컨트롤러테스트에 추가
ㄴ jpa를 mockbean으로해서 있는 것처럼
2) 별도의 클래스를 생성해서 @Cofiguration을 붙일 (앞서 ~Application에 붙인 @EnableJpaAuditing도 여기에 붙임)
3) 슬라이스 테스트가 아닌 @SpringBootTest를 사용해서 풀로 로딩
=> WebApplicationContext를 autowired해서 선언하고
mockMVC를 autowired로 받는 것이 아닌 명시적으로 넣어줌(@BeforeEach 메서드에서 함)
<코드>
@Autowired
private WebApplicationContext was;
private MockMvc mockMvc;
@BeforeEach
void before() {
mockMvc=MockMvcBuilders.webAppContextSetup(wac).build()
}
* 현업에서는 세가지 방법 중 취향마다 갈릴 수 있겠지만 두번째 방법을 사용하면 나 말고 다른 개발자가 1을 하든 3을 하든 아무런 문제가 없다. (나머지는 계속 그 방법을 따라야함)
Entity 캐시
entityManager : JPA에서 제공한 인터페이스, 내부적으로 쿼리메소드, simpleJpaRepository 등 전부 entityManager를 통해 실행
ㄴ 직접적으로 entityManager를 사용하지 않게 스프링에서 알아서 제공함
ㄴ 그러나 SpringDataJpa를 제공하지 않는 기능을 사용하거나 성능이슈 등으로 커스터마이징 하고 싶다면 entityManager를 직접 실행하면 됨.
- EntityManager는 영속성 캐시를 사용함.
따라서 findById 등을 사용하면 한 트랜잭션 내에서 같은 데이터를 여러 번 조회할 때 그만큼 쿼리를 실행하는게 아니라 한번 실행하고 나머지는 캐쉬에서 데이터를 가져온다. (ㅊ
(Jpa의 1차 캐쉬 : 자동으로 entity 캐쉬 처리, map형태(key:엔티티id, value:엔티티) - id조회 후 있으면 db를 조회하지 않고 바로 value를 반환, 없으면 저장하고 보내줌 – id로 조회할때만 적용됨)
ㄴ @Transactional : 유닛테스트 하나를 한 트랜잭션으로 취급
ㄴ 그래서 트랜잭션 내에서는 최대한 db에 반영하는 시간을 늦춤. delete, update등 쿼리가 바로 실행되지 않고 영속성 캐쉬에 쌓아놓다가 한 트랜잭션이 끝날 때 한번에 함
ㄴ save등의 메서드에는 @Transactional이 있는데 테스트 전체를 @Transactional하지 않으면 메서드 하나가 한 트랜잭션이 되어 save문 실행 후에 바로 변경이 적용되고, 전체를 한다면 유닛테스트 하나가 한 트랜잭션이 되어 1)마지막 코드가 끝나고 커밋될 때 auto flush되어 변경이 적용된다.
ㄴ2) flush 메서드를 실행하면 그 때 즉시 db에 반영함(최종 연산으로 update, insert 등의 쿼리 즉시 실행)
ㄴ 한 트랜잭션내에 데이터를 변경을 하고 그것을 db에 반영하기 전에 get으로 조회를 했다면 ?
=> 캐쉬에서 값을 가져오므로 변경이 잘 반영 된 데이터를 가져온다.
ㄴ 3) JPLQuery(엔티티 객체를 대상으로 쿼리)하면 캐쉬전체를 auto flush하고 db에서 가져옴
1) 2) 3)이 캐쉬에서 db로 저장되는 경우 세가지.
Entity 생명주기
EntityManager가 Entity 상태를 어떻게 변화시키는가 ?
* 4가지 상태
: 비영속성상태(new, transient) , 영속상태(managed), 준영속상태(deattached), 삭제상태(removed)
1) 비영속상태(default) : 엔티티매니저가 해당 엔티티를 관리하지 않는 상태(@Transient, db에 저장하지 않은 상태)
2) 영속상태 : =save 영속성컨텍스트가 관리하는 상태, entitimanager.persist로 실현
ㄴ 리파지토리.save메서드 내에서 persist 호출하고 있음
ㄴ 관리된 엔티티의 상태가 변경되면 db에 별도로 반영하지 않아도 트랜잭션이 종료된 후에 영속성 컨텍스트가 저장함(persist는 즉시 되는듯..)
ㄴ 영속성 컨텍스트가 더티체크(변경체크) 함. 영속성 컨텍스트가 가진 엔티티객체는 처음 컨텍스트 로드를 할 때 해당 정보를 일종의 스냅샷으로 가지고 있음.
변경내용이 db에 적용되야 할 때 이 스냅샷과 엔티티의 상태를 비교해서 변경된 부분을 db에 반영 => set만 호출해도 update문 발생
3) 준영속상태 : 영속화된 객체를 분리해서 영속성 컨텍스트 밖으로 꺼냄. 더 이상 관리하지 않음
ㄴ manager.detach로 실현 (JPA에선 메서드로 제공x)
ㄴ 이후에 객체 상태를 변경해도 당연히 db에는 반영되지 않음
ㄴ manager.merge를 하면 변경내용이 반영,(그래도 준영속상태임)
ㄴ clear() = close() : 컨텍스트에 있는 객체들을 모두 detach
ㄴ db에 반영하고 비우려면 clear전에 꼭 flush를 해야함
4) 삭제상태 : =delete
ㄴ manager.remove로 실현
ㄴ merge도 안통함
* 영속성 컨텍스트 관리하에 있는 객체는 더티체크, 1차캐쉬, 쓰기지연 등의 처리를 자동 제공
'BackEnd > 패캠' 카테고리의 다른 글
[JPA] 영속성 전이 – Cascade (0) | 2022.02.04 |
---|---|
[JPA] 트랜잭션 (0) | 2022.02.03 |
[JPA] 연관관계 (0) | 2022.02.01 |
[JPA] EntityListener (0) | 2022.01.31 |
[JPA] QueryMethod 살펴보기 (0) | 2022.01.30 |
Comment