영속성 컨텍스트

이종윤·2022년 2월 10일
0

Spring JPA

목록 보기
13/23

영속성 컨텍스트 알아보자

Persistence Context : 영속성 맥락

✅ 프레임웍에서 주로 컨테이너들이 관리
비슷 스프링의 빌드를 모두 로딩하고 관리하는 작업은 스프링 Context위에서 작동한다. 즉 Persistence Cantainer가 관리하는 내용이라는 의미.

✅ Persistence는 영속, 지속
보통 메모리에 존재하는 데이터는 서비스가 종료되면 사라지는데, 이 데이터를 지속적으로 처리할려면, DB에 저장해야한다. 그래서 데이터를 영속화 하는데 사용하는 컨테이너가 영속성 컨테이너이다.

✅ 실제로 영속성 컨텍스트에 가장 주체적인 역활하는 클래스는 EntityManager 이다. 영속성 컨텍스트의 설정은 퍼시스턴스 XML을 MATA-INF 디렉토리 하위에 생성하여 사용 가능하다. 실제로 xml파일을 로딩하여 Persistence Context, 즉 영속성 맥락들을 사용한다. Persistence.xml 규격을 보면 실제 영속성 컨텍스트를 어떻게 설정하는지 알 수 있다. 하지만 이번에는 스프링부트를 통해 좀 더 편리하게 사용하는 법을 알아보자.

✅ 사실 이때까지 영속성컨텍스트를 설정을 하지 않았지만, JPA를 사용할수 있었다. 왜냐면 spring boot starter data jpa를 의존설정해 주었기 때문이다. 자 이제 springBoot에서application.yml켜서 설정을 해보자.

먼저 MySql 다운로드하고 mysql server 띄워주자.

그리고 jetbrain에서 제공하는 Datagrip을 쓸꺼다.


누락된 드라이버 있으면 다운받고
연결 테스트 한다.
bulid.gradle에 dependencies를 추가해주자.

    runtimeOnly 'mysql:mysql-connector-java'

그리고 쿼리가 되는지 확인하고

book_manager DB를 생성해주자.

select now();

show databases;

create database book_mamager;

Yml에서 datasource를 추가해주자.

spring:
  h2:
    console:
      enabled: true
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true
    defer-datasource-initialization: true
    generate-ddl: true
    hibernate:
      ddl-auto: create-drop

H2 DB 임베드DB로써 TestDB로 많이 쓴다. ddl을 자동으로 생성해주는데, mysql은 상용 DB라서 false로 꺼져있다.
hibernate:ddl-auto 는 none, create-drop, create, validate 제공한다.
✔ none : 제공안함.
✔ create : Persistence Context를 띄울때 Drop하고 DDL 실행
✔ create-drop : DDL 생성하고 Persistence Context 가 종료될때 삭제
✔ updata : 실제 스키마와 엔티티 클래스를 비교해 변경된 Data만 반영, 즉 Drop을 하지 않는다.
✔ vaildate : 단순 비교 작업, 서로 다르면 오류 발생시킴.

contextLoads Test하면 아래의 로그를 찾아볼수 있다.

2022-02-10 17:46:26.547  INFO 4876 --- [    Test worker] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect

🤔 dialect??

dialect(방언)는 entity나 repository에서 사용하는 ORM을 실제로 DB 쿼리로 변환해서 JDBC를 통해 전달하는 것으로 되어있다. 즉, 사이에 자바에서 사용하는 gettser save등등 특정 쿼리로 변경하는데 어떤걸로 변환해야하는지 알아야하고 변환해줘야한다. mysql 이나 h2 db 등등 쿼리는 조금식 다르기 때문이다. 그 역활을 dialect가 해준다.

🤔 그럼 ddl-auto: generate-ddl 차이점??

H2 Test는 기본적으로 generate-ddl을 처리해준다.
운영할때는 ddl-auto를 지양해서 실제로는 none or false를해서 막아버린다.

두가지 차이점에 대해 알아야한다.
generate-ddl은 구현체와 상관없이 자동화된 DDL을 사용할수 있게한다.
ddl-auto가 설정되면 generate-ddl 무시한다.
generate-ddl은 Jpa구현체와 상관없이 사용하는 범용적 옵션이고 ddl-auto는 hibernate에서 제공하는 세밀한 옵션이다.
그리고 H2 DB 같은 임베디드 DB는 ddl-auto: create-drop이 기본이다.

initialization mode


우리가 만들어준 data.sql은 어떻게 실행할까?

  datasource:
    url: jdbc:mysql://localhost:3306/book_manager
    username: ***
    password: ***
    initialization-mode: always

위와같이 하거나.

  sql:
    init:
      mode: always

을 추가해주면된다.

그러면 resources 밑에있는 data.sql파일을 먼저 실행시켜준다.

😈 참고로 실제 서비스할때는 mode: none이라고 명시적으로 해주는 것이 좋다.
🤚 그리고 지금 사용하지 않지만 스키마.sql 파일도 resources밑에 넣어주면 ddl이 실행되는데 그럼

    hibernate:
      ddl-auto: create-drop

이녀석은 무시된다는 점 참고하자.

그리고 이때까지 했던 Test를 모두 시켜보자(통합Test)

🤔 그럼 몇몇의 애러가 뜰탠데 Data들이 겹쳐서 일어나는 애러가 있을것이다.
그래서 각각의 Test를 할 때마다 다시 rollback시켜주는 @Transactional 를 달아주면된다.


@SpringBootTest
@Transactional
class UserRepositoryTest {

🤔 그리고 몇몇가지 애러를 또 고쳐보자.

JPA metamodel must not be empty!

이라고 뜨는데 이 애러는
@WebMvcTest는 SliceTest라고하는데 전체 spring context를 로딩하지않고 웹 컨트롤러에대한 일부 Bean들만 로딩해서 Test를 해서 JPA 옵션에서 발생하는 문제이다.

해결 방법은 3가지가 있다.
👉 1번쨰는

@WebMvcTest
@MockBean(JpaMetamodelMappingContext.class)
class HelloControllerTest {
...
...
}

이렇게 하면 된다.
왜냐하면 여기 Controller에서는 JPA관련이 필요없기때문에 로딩을 할수 없었다.
HelloControllerTest 클래스 부분을 @MockBean(JpaMetamodelMappingContext.class)
을 넣어 마치 있는것 처럼 하여 막아주면서 동작을 시킨다.

👉 2번째는

@Configuration
@EnableJpaAuditing
public class JpaConfiguration {
}

👉 3번째는

sliceTest를 안하고 FullSpringBootTest사용

//@WebMvcTest
//@MockBean(JpaMetamodelMappingContext.class)
@SpringBootTest
class HelloControllerTest {
    //    @Autowired
//    private MockMvc mockMvc;
    @Autowired
    private WebApplicationContext wac;
    private MockMvc mockMvc;

    @BeforeEach
    void before() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

WebMvcTest에서 만들어준 mockmvc를 직접만들어 주는 방법이다.

2번째 방법이 가장 좋다.

profile
OK가자

0개의 댓글