본문 바로가기
Web/Spring

[Spring-boot JPA] @Entity, @Id, save 예제

by EricJeong 2019. 9. 5.

JPA는 DBMS와 Java를 연결해주는 ORM의 일종입니다.

계속 쓰이던 MyBatis와의 차이점은, 객체 지향적으로 데이터베이스를 사용할 수 있다는 점입니다.

 

컬렉션에서는 꺼낸 객체의 값을 변경한다면 그 객체를 다시 컬렉션에 저장하지 않아도 자동으로 그 객체의 값이 변합니다.

JPA의 영속 컨텍스트는 자신이 관리하는 객체의 값이 변경하는것을 감지하여 값이 변한다면 DB에 UPDATE문을 통해 값을 같이 변경시킵니다.

 

예제를통해 살펴보겠습니다.

Spring Starter Project로 Spring-boot 프로젝트를 만들어주세요.

 

각 항복은 다음과 같이 입력해주세요.

 

 

JPA를 사용하기 위해서 내장 데이터베이스인 H2, JPA 의존성인 Spring Data JPA, 웹을 사용하기 위한 Spring Web Starter를 추가해주세요.

 

 

 

 

 

 

 

application.properties 파일에 JPA가 보내는 쿼리를 확인하기 위해 다음 속성을추가해주세요.

# JPA
spring.jpa.show-sql=true

 

 

hello 패키지를 만들어 주신 후  MemberVO클래스를 만들어주세요.

 

 

 

MemberVO.java

package me.eric.hello;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class MemberVO {
	@Id
	private String id;
	private String name;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

 

@Entity

어노테이션 @Entity는 JPA에서 관리할 객체를 선언합니다.

 

@Id

어노테이션 @Id는 객체의 Primary Key를 의미합니다.

JPA는 이 id를 통해 객체를 구분합니다.

 

 

지금 이 상태로 Spring 프로젝트를 실행시킨다면 어떻게 될까요?

다음과 같은 쿼리를 로그에서 확인하실 수 있습니다.

 

2019-09-05 09:44:04.703  INFO 6384 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-09-05 09:44:04.804  INFO 6384 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-09-05 09:44:04.844  INFO 6384 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2019-09-05 09:44:04.884  INFO 6384 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.3.10.Final}
2019-09-05 09:44:04.885  INFO 6384 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2019-09-05 09:44:05.054  INFO 6384 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2019-09-05 09:44:05.162  INFO 6384 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Hibernate: drop table membervo if exists
Hibernate: create table membervo (id varchar(255) not null, name varchar(255), primary key (id))
2019-09-05 09:44:05.535  INFO 6384 --- [           main] o.h.t.schema.internal.SchemaCreatorImpl  : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@45545e7a'
2019-09-05 09:44:05.537  INFO 6384 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-09-05 09:44:05.678  INFO 6384 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'

 

JPA에서는 @Entity 어노테이션을 통해 자동으로 테이블을 생성해줍니다.

따로 CREATE문을 만들지 않아도 자동으로 테이블을 만들어 주는 것이죠.

 

하지만 쿼리를 자세히 보면 'drop table'을 확인할 수 있는데, 이것은 기존에 존재하던 테이블을 지우고 다시 create를 시킨다는 의미입니다.

 

당연히 내부에 있는 데이터는 모두 초기화가 되겠죠

 

그렇기 때문에 저장한 데이터를 그대로 가지고 있고 싶다면 다음 속성을 application.properties에 추가하면 됩니다.

spring.jpa.hibernate.ddl-auto=update

spring.jpa.hibernate.ddl-auto는 프로젝트 시작, 종료시 DDL을 어떻게 실행시킬지에 대한 옵션입니다.

이것을 update로 놓고 시작한다면 @Entity와 내부 DB의 테이블 컬럼을 비교하여 바뀐 부분을 자동으로 추가해줍니다.

 

그리고 DROP TABLE문을 실행시키지도 않습니다.

위 옵션은 다음과 같이 변경할 수 있습니다!

 

1. none - 테이블을 자동으로 생성하지 않습니다.

2. create - 테이블을 항상 다시 생성합니다.

3. create-drop - 프로젝트 실행 시 테이블을 생성하고 프로젝트 종료시 테이블을 삭제합니다.

4. update - 프로젝트 실행 시 @Entity 클래스와 DB내부 스키마를 비교합니다. 만약 스키마와 @Entity가 다르다면 컬럼을 주가합니다. 단 컬럼 삭제는 진행하지 않습니다.

5. validate - 프로젝트 실행 시 @Entity와 DB내부 스키마를 비교해서 같으면 정상적으로 실행시키고 다르면 예외를 발생시킵니다.

 

 

 

 

이제 DB와 연결하는 Dao를 만들어보겠습니다

IMemberDao라는 인터페이스를 hello패키지에 만들어주세요.

Ioc컨테이너에서 관리할 수 있도록 @Repository를 추가해주세요.

 

package me.eric.hello;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface IMemberDao extends JpaRepository<MemberVO, String>{
	
}

 

JPA를 이용하는 Dao는 JpaRepository 인터페이스를 상속해야 합니다. 제네릭 타입은 관리하는 Entity와 그 Entity의 기본키 타입입니다.

 

MemberVO의 클래스와 Id의 타입인 String을 넣어주세요.

그리고 이제 DB와 연결된 것을 확인하기 위해 Controller 클래스를 만들어주세요.

 

package me.eric.hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
	@Autowired
	private IMemberDao memberDao;
	
	@GetMapping("/save")
	public String index() {
		MemberVO member = new MemberVO();
		member.setId("memberID-1");
		member.setName("memberName-1");
		
		System.out.println("member-1 저장 코드 시작");
		memberDao.save(member);
		System.out.println("member-1 저장 코드 끝");

		
		
		return "member변경! 로그를 확인해보세요.";
	}
}

 

그리고 localhost:8080/save 로 접속하시면 다음과 같은 결과가 로그에 남습니다.

 

member-1 저장 코드 시작
Hibernate: select membervo0_.id as id1_0_0_, membervo0_.name as name2_0_0_ from membervo membervo0_ where membervo0_.id=?
Hibernate: insert into membervo (name, id) values (?, ?)
member-1 저장 코드 끝

 

그저 Dao에 인터페이스를 상속하기만 하고 save 메서드를 실행했을 뿐인데 자동으로 쿼리를 작성하여 DB에 저장하는 것을 확인할 수 있습니다!

 

 

 

댓글