JPA 프로그래밍 - 1 (스프링 데이터 JPA - 2)
1. 개요 (기본)
- 의존성 추가 (spring data JPA와 관련된 빈들이 모두 등록됨)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
- application.properties 추가
spring.datasource.url=jdbc:postgresql://localhost:5432/springdata
spring.datasource.username=hongchan
spring.datasource.password=pass
spring.jpa.hibernate.ddl-auto=create //update, validate
// 개발할 때는 create, 이후에는 validate 사용을 권장!
// update는 스키마 수정 시 지저분해질 수 있는 우려가 있음! 조심해서 사용
- 도메인 Account 객체 생성 @Entity
@Entity
public class Account {
@Id @GeneratedValue
private Long id;
private String username;
private String password;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsernmae() {
return username;
}
public void setUsernmae(String usernmae) {
this.username = usernmae;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- JPA API 사용하기
@Component
@Transactional // persist 사용 시 트랜잭션으로 처리해야 함
public class JpaRunner implements ApplicationRunner {
@PersistenceContext
EntityManager entityManager; // JPA API에서 가장 핵심적인 것
@Override
public void run(ApplicationArguments args) throws Exception {
Account account = new Account();
account.setUsernmae("jiyun");
account.setPassword("1234");
entityManager.persist(account);
}
}
- Hibernate API 사용하기
@Component
@Transactional
public class JpaRunner implements ApplicationRunner {
@PersistenceContext
EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Account account = new Account();
account.setUsernmae("jiyun2");
account.setPassword("hibernate");
Session session = entityManager.unwrap(Session.class); // 핵심적인 API
session.save(account);
}
}
2. 엔티티 맵핑
@Entity
- 객체 세상에서 부르는 이름 (보통 클래스와 같은 이름을 사용하기 때문에 잘 변경하지 않음)
@Table
- 릴레이션 세상에서 부르는 이름
- @Entity의 이름이 기본 값
- 테이블의 이름은 SQL에서 쓰임
@Id
- 엔티티의 PK를 맵핑할 때 사용
@GeneratedValue
- PK의 생성 방법을 맵핑하는 애노테이션
@Column
- 보통 생략되어 있고, 추가적으로 명시할 때 사용
- (nullable = false, unique = true)
@Temporal
- Date, Calender
@Transient
- 컬럼으로 맵핑하고 싶지 않은 멤버에 추가
- 실행되는 SQL 문을 확인하는 설정 추가
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
3. Value 타입 맵핑
- Account 엔티티 타입 안에 있는 멤버들(id, username, password)
- 기본 타입, Composite Value 타입, Collection Value 타입
Composite Value 타입 맵핑
- @Embadable
- @Embadded
- @AttributeOverrides
- @AttributeOverride
@Embeddable
public class Address {
private String city;
private String state;
private String street;
}
@Entity
public class Account {
@Id @GeneratedValue
private Long id;
...
@Embedded
private Address address;
}
// 실행된 SQL
create table account (
id int8 not null,
city varchar(255),
state varchar(255),
street varchar(255),
password varchar(255),
username varchar(255),
primary key (id)
)
4. 1대다 맵핑
- 관계에는 항상 두 엔티티가 존재함
- 둘 중 하나는 그 관계의 주인이고, 다른 쪽은 종속된 쪽이다.
- 해당 관계의 반대쪽 레퍼런스를 가지고 있는 쪽이 주인
@ManyToOne
- Study 가 이 관계에서 주인이 됨. (단방향에서는 관계를 정의한 쪽이 주인)
- 종속된 쪽의 PK를 FK로 설정함
(Getter Setter 생략)
- Account.java
@Entity
public class Account {
@Id @GeneratedValue
private Long id;
private String username;
private String password;
}
- Study.java
@Entity
public class Study {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne
private Account owner;
}
@OneToMany
- Account가 관계의 주인이 됨 (단방향에서는 관계를 정의한 쪽이 주인)
- Join 테이블 생성 'account_studies'
- Account.java
@Entity
public class Account {
@Id @GeneratedValue
private Long id;
private String username;
private String password;
@OneToMany
private Set<Study> studies = new HashSet<>();
}
- Study.java
@Entity
public class Study {
@Id @GeneratedValue
private Long id;
private String name;
}
양방향 관계
- 기본적으로 FK를 가진쪽(@ManyToOne)이 주인이 됨!
- @OneToMany 쪽에 mappedBy를 사용해 관계를 맺고 있는 필드를 설정해주어야 함!! (주인한테 관계를 설정해야 DB에 반영이 됨)
- Account.java의 addStudy, removeStudy 메소드 처럼 구현하여 보통 양쪽에 데이터를 넣거나 삭제시켜 일치시킴.
-> 주인인 쪽에만 설정하면 DB에 반영이 되지만 양방향을 고려하여 양쪽에 데이터를 일치시킴
- Account.java
@Entity
public class Account {
@Id @GeneratedValue
private Long id;
private String username;
private String password;
@OneToMany(mappedBy = "owner")
private Set<Study> studies = new HashSet<>();
...
public void addStudy(Study study) {
this.getStudies().add(study);
study.setOwner(this); // 주인에 설정
}
public void removeStudy(Study study) {
this.getStudies().remove(study);
study.setOwner(null); // 주인에 설정
}
}
- Study.java
@Entity
public class Study {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne
private Account owner;
}
인프런 백기선님 '스프링 데이터 JPA’ 강의를 듣고 정리한 내용입니다.