인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

빛혜원님의 프로필 이미지
빛혜원

작성한 질문수

실전! 스프링 데이터 JPA

스프링 데이터 JPA와 DB 설정, 동작확인

h2 데이터베이스 관련 문제

작성

·

1.6K

·

수정됨

0


1. 강의 내용과 관련된 질문인가요? (예)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)

[질문 내용]
질문 1)

실전 스프링 Data JPA -

섹션 1. 프로젝트 환경설정 -스프링 데이터 JPA와 DB설정, 동작확인 강의에서

H2 데이터베이스 설치 후 , 동일하게 memberJpaRepositoryTest 한 후

H2 데이터베이스 다시 접속하여 확인하여도 , member table 이 생성되어 있지 않습니다.

콘솔창에 찍히는걸 봤을때는 insert까지 잘 된것을 확인했습니다만

무엇이 문제일까요?

[Member ].class

package com.example.datajpa.entity;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import lombok.Getter;

@Entity

@Getter

public class Member {

  @Id

  @GeneratedValue(strategy = GenerationType.IDENTITY)

  @Column(name = "id", nullable = false)

  private Long id;

  private String name;

  public Member(String name) {

    this.name = name;

  }

  //디폴트값으로 private 하기엔 프록시 생성시 사용되어야 함으로 protected 제어자를 통해 다른곳에서 만들지 못하도록함

  protected Member() {

  }

}

[MemberJpaRepository] .class

@Repository

public class MemberJpaRepository {

  @PersistenceContext

  private EntityManager em; //jpa의 영속성컨텍스트를 관리 하는 엔티티메니저, 이것에 의해 데이터를 관리함.

  public Member save(Member member ){

    em.persist(member);// 영속화

    return member;

  }

  public Member find(Long id){

    return em.find(Member.class,id);

  }

}

[MemberJpaRepositoryTest] .class

@SpringBootTest

@Transactional // 테스트가 끝난후 데이터를 롤백하기  위해

@Rollback(false) // 만약 롤백을 원하지 않을경우엔 이 어노테이션을 사용함, 실전에서는 ! 사용 노노!

class MemberJpaRepositoryTest {

  @Autowired

  MemberJpaRepository memberJpaRepository;

  @Test

  public void testMember(){ //public 생략가능

    Member member = new Member("memberA");

    Member savedMember = memberJpaRepository.save(member);

    Member findMember = memberJpaRepository.find(savedMember.getId());

    assertThat(findMember.getName()).isEqualTo(member.getName());

    assertThat(findMember.getId()).isEqualTo(member.getId());

    assertThat(findMember).isEqualTo(member);

  }

}

[application.yml]

spring:

  datasource:

  url: jdbc:h2:tcp://localhost/~/datajpa

  username: sa

  password:

  driver-class-name: org.h2.Driver

jpa:

  hibernate:

    ddl-auto: create

    # 객체를 보고 자동으로 테이블 생성 여부. 생성 - create, 비생성 - none

    # 테스트이기 때문에 create로 설정하며

    # 실제로는 none 으로 합니다. create이면 기존의 테이블을 전부 밀어버립니다.

  properties:

    hibernate:

      show_sql: true

      format_sql: true

    logging.level:

      org.hibernate.SQL: debug

    # 콘솔창에 파라미터 값을 보고 싶을때 주로 개발할때, 실전에서는 성능저하 가능성 고려하여 사용해야함.

      org.hibernate.type: trace

    #implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.7' 외부라이브러리 추가하면깔끔하게 파리미터값을 보여준다.

  # show_sql : 옵션은 System.out 에 하이버네이트 실행 SQL을 남긴다.

  # org.hibernate.SQL : 옵션은 logger를 통해 하이버네이트 실행 SQL을 남긴다.

[build gradle]

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    implementation 'org.springframework.boot:spring-boot-starter-web'

    compileOnly 'org.projectlombok:lombok'

    //h2사용

    runtimeOnly 'com.h2database:h2'

[콘솔창]

insert into member (id, name) values (default, ?)

insert into member (id, name) values (default, 'memberA');

2023-05-26 18:33:03.071  INFO 3250 --- [           main] p6spy                                    : #1685093583071 | took 0ms | commit | connection 4| url jdbc:h2:mem:ca9facbe-0495-462f-a2eb-d8f9f1d14ecd

;

2023-05-26 18:33:03.072  INFO 3250 --- [           main] o.s.t.c.transaction.TransactionContext   : Committed transaction for test: [DefaultTestContext@3b0c9195 testClass = MemberJpaRepositoryTest, testInstance = com.example.datajpa.repository.MemberJpaRepositoryTest@3f6a9ba0, testMethod = testMember@MemberJpaRepositoryTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@366c4480 testClass = MemberJpaRepositoryTest, locations = '{}', classes = '{class com.example.datajpa.DataJpaApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@5c86dbc5, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@5f9edf14, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@a8ef162, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@78fa769e, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@536dbea0, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@6b26e945], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]

2023-05-26 18:33:03.096  INFO 3250 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'

2023-05-26 18:33:03.097  INFO 3250 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'

2023-05-26 18:33:03.101  INFO 3250 --- [ionShutdownHook] p6spy                                    : #1685093583101 | took 2ms | statement | connection 5| url jdbc:h2:mem:ca9facbe-0495-462f-a2eb-d8f9f1d14ecd

drop table if exists member CASCADE

drop table if exists member CASCADE ;

2023-05-26 18:33:03.106  INFO 3250 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...

2023-05-26 18:33:03.115  INFO 3250 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Process finished with exit code 0

질문 2.  이 강의를 보기 전에는 h2데이터베이스 별도 설치 없이

아래와 같이 Application.yml 설정과

Build.gradle에 의존성만 지정하여

브라우저에서 Localhost:8080/h2-console 치면  h2 데이터베이스를 사용할 수 있었습니다.

하지만 이 강의를 따라 h2 설치 후엔  Localhost:8080/h2-console 해도 500에러만 발생합니다. 이유가 뭘까요 ㅠㅠ

[application.yml]

# h2

  datasource:

    driver-class-name: org.h2.Driver

    url: jdbc:h2:mem:db;MODE=MYSQL;

    username: sa

    password:

[build gradle]

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    implementation 'org.springframework.boot:spring-boot-starter-web'

    compileOnly 'org.projectlombok:lombok'

    //h2사용

    runtimeOnly 'com.h2database:h2'

답변 4

0

저도 같은 문제를 겪었는데 yml 파일 들여쓰기를 제대로 하고 문제 해결하였습니다.

0

안녕하세요. 빛혜원님, 공식 서포터즈 OMG입니다.
.

1.
의심가는 부분이 있다면 application.properties의 ddl-auto가 create가 되어 애플리케이션(테스트) 실행 시점에 테이블을 drop하고 있지 않나 생각합니다.

none으로 변경해보시겠어요?

 

2.

테스트 환경에서 실행하였다면 테스트가 끝난 후 서버는 종료되기 때문에 h2-console에 접속하지 못합니다.

테스트가 아닌 애플리케이션서버를 실행하신걸까요?

(XXXApplication.java에서 실행)

.
감사합니다.

0

안녕하세요, 인프런 AI 인턴이에요.

질문1) 문제는 Member 클래스의 생성자에서 매개변수를 받아오지 않는 생성자를 protected 제어자를 통해 선언하여 JPA의 프록시 기술이 동작하도록 설계되었다는 것입니다. 따라서 Member 클래스를 사용하는 부분에서 Member 객체를 직접 new 연산자로 생성하지 않고, memberRepository.save()와 같은 JPA의 EntityManager.persist() 메소드를 사용하여 객체를 만들어야 합니다. 그렇지 않으면 정확한 프록시 처리가 되지 않습니다.

질문2) 강의에서는 H2 데이터베이스를 설치하고 설정파일(application.yml)에서 URL을 포트와 함께 지정하였기 때문에, localhost:8080/h2-console로 접속하는 것이 아닌 localhost:8080 으로 접속해야 합니다. 이후 H2 데이터베이스 관리 화면에서는 JDBC URL을 입력할 때, jdbc:h2:tcp://localhost/~/datajpa와 같이 차이가 있을 수 있습니다. 또한, create, update, validate 등의 DDL Auto 옵션을 올바로 설정하는지 확인해야 합니다.

그 외에도 프로젝트 내부에 H2 데이터베이스 파일이 저장되는 경로에 따라서 DB 파일을 찾지 못하는 경우가 있습니다. 따라서 데이터베이스 경로 지정에 유의하여 설정해보시기 바랍니다.

감사합니다.

-2

1번은 [application.yml]의

spring:  

ㄴ datasource:  

이 아래부터 들여쓰기가 안맞아서 inmemory로 동작하는것 같습니다. url, username, password, driver-class-name 옵션을 datasource의 하위에 오도록 한칸씩 들여쓰기 해주세요

빛혜원님의 프로필 이미지
빛혜원

작성한 질문수

질문하기