본문 바로가기

STUDY/Spring

Spring Boot | JPA 사용해보기 (1) + H2데이터베이스 설치

이 글은 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의를 매우 많이 참고했습니다.

H2 데이터베이스

간단한 테스트만 할 것이므로 H2데이터베이스로 진행해 보겠섬니다..! MacOSbrew로 휘리리릭
다른 운영체제는 위에 링크 걸어놓았으니.. 링크로 다운로드 혹은 뭐 초콜라테이,,,이런거로 설치하면 된다.

h2설치

$ brew install h2

h2 실행!! 중요!

$ h2

아래처럼 콘솔이 뜨면 잘 실행된 것이에요.. sessionid는 지우면 안됩니다!

JDBC URL을 아래와 같이 변경하고 연결해서 성공하면 끝

스프링 부트 스타터로 프로젝트 생성

build.gradle참고 (lombok은 꼭 사용하지 않아도 된다)

plugins {
    id 'org.springframework.boot' version '2.4.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'demo'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

application.yml 설정

  • show-sql은 Hibernate에서 sql을 실행할 때 마다 실행한 쿼리문을 보여주도록 설정한 값
  • ddl-autocreate-drop은 만약 테이블이 없으면 생성하도록 설정한 값
    spring:
    datasource:
      url: jdbc:h2:tcp://localhost/~/test
      driver-class-name: org.h2.Driver
      username: sa
    jpa:
      show-sql: true
      hibernate:
        ddl-auto: create-drop

Member Entity작성

아주 간단한 멤버 테이블과 매핑될 클래스를 작성해본다.

  • @Entity 어노테이션을 달면 자동으로 member클래스와 매핑된다!
  • 위에서 설정을 create-drop으로 해줬기 때문에 member테이블이 없어도 자동으로 생성!
  • @Getter는 롬복을 이용해 getter메서드를 생성한 것
  • @NoArgsContructor는 기본 생성자(빈 생성자)를 자동으로 생성해주는데, 접근제한자를 protected로 설정한다
  • @Id는 테이블의 primary key 컬럼과 매핑된다
  • @GeneratedValue는 pk생성 규칙을 설정한 것인데 기본값은 AUTO이다

GenerationType

  • AUTO(default): JPA구현체(Hibernate)가 적절한 생성 전략을 선택해 생성(Java 변수 타입에 따라)
  • IDENTITY: 데이터베이스가 생성
  • SEQUENCE: 데이터베이스의 시퀀스를 사용해 기본키 생성
  • TABLE: 기본키 값을 데이터베이스 테이블을 사용해 생성
    참고
    @Entity // 테이블과 링크될 클래스임을 나타냄
    @Getter
    @NoArgsConstructor(access = AccessLevel.PROTECTED)  // 기본 생성자의 접근 권한을 protected로 제한함
    public class Member {

    @Id // 해당 테이블의 PK 필드
    @GeneratedValue(strategy = GenerationType.IDENTITY) // PK생성규칙
    private Long id;
    private String name;

    }

Entity는 기본적으로 자바 클래스와 관계형 데이터베이스 테이블을 매칭한다.
@Entity 어노테이션을 붙여 사용한다.
해당 클래스의 필드(멤버변수)들은 해당 테이블의 행(column)과 매칭된다.

Repository작성

interface로 작성해준 뒤

public interface MemberRepository {

    List<Member> findAll();

}

상속받아 구현 클래스를 작성해준다.
EntityManager@RequiredArgsConstructor를 통해 생성자로 의존성 주입 해주었다.


@Repository  
@RequiredArgsConstructor  
public class MemberRepositoryImpl implements MemberRepository {

private final EntityManager em;

@Override  
public List findAll() {  
    return em.createQuery("select m from Member m", Member.class)  
            .getResultList();  
}

}

Service작성

서비스는 뭐.. 휘리리리릭
@Transactional어노테이션을 붙여줘야 한다!

@Transactional  
@Service  
@RequiredArgsConstructor  
public class MemberService {

private final MemberRepository repository;

public List findAll() {  
    return repository.findAll();  
}

}

Controller작성

@RequiredArgsConstructor  
@RestController  
public class WebController {

private final MemberService service;

@GetMapping("/")  
public String hello() {  
    return "hello";  
}

@GetMapping("/members")  
public ResponseEntity<?> members() {  
    List members = service.findAll();  
    return new ResponseEntity<>(members, HttpStatus.OK);  
}

}

테스트


이제 DB에 INSERT도 진행해보자..

Repository, Service작성

interface에 추가


public interface MemberRepository {

List<Member> findAll();  
Member save(Member member);

}

구현코드 작성! persist(...)INSERT를 해준다.


@Repository  
@RequiredArgsConstructor  
public class MemberRepositoryImpl implements MemberRepository {

private final EntityManager em;

@Override  
public List findAll() {  
    return em.createQuery("select m from Member m", Member.class)  
            .getResultList();  
}

@Override  
public Member save(Member member) {  
    em.persist(member);  
    return member;  
}

}

서비스에서 @Transactional어노테이션이 추가되었다.


@Transactional  
@Service  
@RequiredArgsConstructor  
public class MemberService {

private final MemberRepository repository;

public List findAll() {  
    return repository.findAll();  
}

public Member join(Member member) {  
    return repository.save(member);  
}

}

Controller작성 + 테스트

POST메서드로 멤버 값을 보내면 MEMBER테이블에 저장되어야 한다!

@PostMapping("/members")  
public ResponseEntity<?> joinMember(@RequestBody Member member) {  
    log.info("join member: " + member);  
    service.join(member);  
    return new ResponseEntity<>(member, HttpStatus.OK);  
}

이름만 보냈고, 성공해서 결과값으로 저장한 값이 왔다.

id는 보내지 않았는데.. JPA에서 INSERT에 성공하면 자동으로 INSERT ID를 세팅해준다... 크...

GET으로 확인해보자

DB에도 당연히..