[Spring boot & JPA] 01. 프로젝트 환경 설정

PADO·2021년 1월 26일
0

Spring boot & JPA

목록 보기
2/6
post-thumbnail

🌱 프로젝트 환경 설정

목차

  • 프로젝트 생성
  • 라이브러리 살펴보기
  • View 환경설정
  • H2 데이터베이스 설치
  • JPA와 DB 설정, 동작 확인

 

프로젝트 생성

  • 스프링 부트 스타터 (start.spring.io)
    • groupId: jpabook
    • artifactId: jpashop
  • 사용 기능: web, thymeleaf, jpa, h2, lombok
    • Spring Web Starter: web 애플리케이션 개발에 필요
    • thymeleaf: 모던 서버사이드 자바 템플릿 엔진
    • Spring Data JPA: 자바 Persistence API using Spring Data and Hibernate
    • h2: 내장해 쉽게 실행할 수 있는 Database
    • lombok: 간단한 어노테이션으로 반복되는 코드를 줄여주는 기능

프로젝트 다운로드 후 IntelliJ로 Import or Open

  • 프로젝트를 실행해보면 tomcat이 8080 port에서 실행이 되었다는 로그가 뜸

  • IntelliJ > Preference > Plugins > Lombok

  • IntelliJ > Preference > Build, Execution, Deployment > Compiler > Annotation Processors

  • Enable annotation processing 선택

 

라이브러리 살펴보기

Project에서 아래와 같이 실행하면 의존관계를 보여줌

$ ./gradlew dependencies

IntelliJ의 우측 Gradle 탭에서도 dependency 확인 가능

  • spring-boot-starter-web 아래엔 embedded된 tomcatwebmvc가 있음.

Tomcat은 Java를 이용한 웹 애플리케이션의 다양한 규격(Spec)을 준수하여 JSP, HTML 파일들로 구성된 .war 파일(애플리케이션의 파일들을 압축해놓은 하나의 파일)을 배포해주는 엔진

  • spring-boot-starter-data-jpa 아래엔 core, aop, jdbc, HikariCP(커넥션 풀), hibernate, logging(logback, slf4j- logger를 찍는 인터페이스들의 모음) 등이 있음.
  • Test에서 spring-boot-starter-test에는 junitmockito, assertj등이 있음.

핵심 라이브러리

  • Spring MVC
  • Spring ORM
  • JPA, 하이버네이트
  • 스프링 데이터 JPA

기타 라이브러리

  • H2 데이터베이스 클라이언트
  • 커넥션 풀 (boot 기본은 HikariCP)
  • WEB (thymeleaf)
  • 로깅 SLF4J & LobNack
  • 테스트

 

View 환경 설정

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Hello</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'안녕하세요. ' + ${data}" >안녕하세요. 손님</p>
</body>
</html>

순수 html 렌더링 시 "안녕하세요. 손님"이 출력, 서버 사이드 렌더링 시 안녕하세요. data가 출력.

  • 정적 페이지 index.html 하나 만들기 static/index.html
<!DOCTYPE HTML>
  <html xmlns:th="http://www.thymeleaf.org">
       
     <head>
        <title>Hello</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>
    <body>
    Hello
    <a href="/hello">hello</a>
    </body>
</html>

참고) spring-boot-devtools 라이브러리를 추가하면, html 파일을 컴파일만 해주면 서버 재시작 없이 View 파일 변경이 가능하다.

implementation 'org.springframework.boot:spring-boot-devtools'

html 파일 컴파일 방법: 메뉴 build → Recompile

 

H2 데이터베이스 설치

개발이나 테스트 용도로 가볍고 편리한 DB, 웹 화면 제공

  • 데이터베이스 파일 생성 방법
    • jdbc:h2:~/jpashop (최소 한번, 세션키 유지한 상태로 실행)
    • ~/jpashop.mv.db 파일 생성 확인
    • 이후 부터는 jdbc:h2:tcp://localhost/~/jpashop 이렇게 접속

 

JPA와 DB 설정, 동작 확인

**main/resources/application.yml**

spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/jpashop;MVCC=TRUE
    username: sa
    password:
    driver-class-name: org.h2.Driver

  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
#        show_sql: true
        format_sql: true

logging:
  level:
    org.hibernate.SQL: debug
  • ddl-auto: create 옵션은 애플리케이션 실행 시점에 테이블을 drop 하고, 다시 생성한다.
  • show_sql 옵션은 System.out 에 하이버네이트 실행 SQL을 남긴다.
  • org.hibernate.SQL 옵션은 logger를 통해 하이버네이트 실행 SQL을 남긴다.

주의) application.yml 같은 yml 파일은 띄어쓰기(스페이스) 2칸으로 계층을 만든다.

동작 하는지 확인하기

회원 엔티티

@Entity
@Getter @Setter
public class Member {

    @Id @GeneratedValue
    private Long id;
    private String username;

}

회원 리포지토리

@Repository
public class MemberRepository {

    @PersistenceContext
    private EntityManager entityManager;

    public Long save(Member member) {
        entityManager.persist(member);
        return member.getId();
    }

    public Member findById(Long id) {
        return entityManager.find(Member.class, id);
    }
}

@PersistenceContext 어노테이션이 있으면, 스프링 부트가 엔티티 매니저를 생성해 주입 시켜준다.

  • save()에서 Member가 아닌 Member.getId()를 반환하는 이유: 커맨드와 쿼리를 분리하라
    저장은 side effect를 일으킬 수 있는 커맨드이기 때문에 리턴값을 거의 만들지 않는다. Id 정도 있으면 다음에 다시 조회할 수 있으니 Id만 반환하게 한다.

테스트

MemberRepository의 test니 @Autowired로 memberRepository Injection을 받는다.

@RunWith(SpringRunner.class)
@SpringBootTest
public class MemberRepositoryTest {

    @Autowired
    MemberRepository memberRepository;

    @Test
    public void save() {
        //given
        Member member = new Member();
        member.setUsername("member1");

        //when
        Long savedId = memberRepository.save(member);
        Member findMember = memberRepository.findById(savedId);

        //then
        Assertions.assertThat(savedId).isEqualTo(findMember.getId());
        Assertions.assertThat(member.getUsername()).isEqualTo(findMember.getUsername());
		    Assertions.assertThat(findMember).isEqualTo(member);
		}
}

테스트 실행 시 에러: No EntityManager with actual transaction available for current thread
→ EntityManager를 통한 모든 데이터 변경은 항상 transaction 안에서 이루어져야 한다.
→ (Repository 또는 메서드에 @Transactional을 걸 수 있지만) 일단 Test에 추가해준다.

테스트 성공: H2 데이터베이스에 Member 테이블이 생성된 것을 확인할 수 있다.
@Transactional 어노테이션이 테스트에 있으면 테스트 후 Rollback을 하므로, 저장된 데이터는 없다.
@Rollback(false) 어노테이션 추가 시 Rollback없이 커밋해 테스트 내용이 DB에 저장된다.

Assertions.assertThat(findMember).isEqualTo(member); 결과는 두 객체가 동일
→ 같은 트랜잭션 안에서 데이터를 조회하고 저장하면 영속성 컨텍스트가 동일하다. 같은 영속성 컨텍스트 안에서는 id(식별자)값이 같으면 같은 엔티티로 식별한다. 1차 캐시에 저장된다.

쿼리 파라미터 로그 남기기

  • org.hibernate.type: trace

쿼리 상에는 "?"로 남지만 SQL 실행 파라미터를 로그로 남긴다.

implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'

참고) 쿼리 파라미터를 로그로 남기는 외부 라이브러리는 시스템 자원을 사용하므로, 개발 단계에서는 편하 게 사용해도 된다. 하지만 운영시스템에 적용하려면 꼭 성능테스트를 하고 사용하는 것이 좋다.

0개의 댓글