2. JPA 시작
2장. JPA 시작
프로젝트 세팅
책에서는 Eclipse로 진행하지만, 깔기 귀찮으므로 IntelliJ에서 진행하였다.
IntelliJ에서 Maven 프로젝트 생성
책에서는 Eclipse로 진행하지만, 깔기 귀찮으므로 IntelliJ에서 진행하였다.
H2 데이터베이스 설치
1.4.198 버전 이후로는 보안문제로 데이터베이스가 자동 생성되지 않기 때문에 데이터베이스를 직접 생성해야 한다.
brew install h2
h2
-
Embedded 모드로 연결 시험 후, Server모드로 실행하면 정상적으로 동작한다. (안되면 껏다가 다시 켜보자)
-
예제 테이블 생성
라이브러리와 프로젝트 구조
- Maven
자바용 프로젝트 관리 도구 관리 도구로, 라이브러리 관리기능, 빌드 기능 등이 포함되어 있다. - pom.xml
Maven의 설정 파일이다.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>JPA_STUDY</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.6.5.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.210</version>
</dependency>
</dependencies>
</project>
객체 매핑 시작
package jpabook.start;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "MEMBER")
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME")
private String username;
// 매핑 정보가 없는 필드
private Integer age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
@Entity
해당 클래스를 테이블과 매핑한다는 것을 JPA에 알려준다. 이를 엔티티 클래스 라고 한다@Table
엔티티 클래스에 매핑할 테이블 정보를 알려준다.name
속성을 통해 Member 엔티티를 MEMBER 테이블에 매핑하였으며, 생략시 클래스 이름을 테이블 이름으로 매핑한다.@Id
Pirmary Key(기본키)를 매핑한다.@Id
가 사용된 필드를 식별자 필드라고 한다.@Column
필드를 컬럼에 매핑한다.name
속성을 사용해 Member 엔티티의 username 필드를 MEMBER 테이블의 NAME 컬럼에 매핑하였다.- 매핑 정보가 없는 필드
매핑 어노테이션이 생략되면, 필드명을 사용해서 컬럼명으로 매핑한다. 데이터베이스가 대소문자를 구분한다면name
속성으로 명시적으로 매핑하여야 한다.
persistence.xml 설정
- JPA는 persistence.xml을 사용하여 필요한 설정 정보를 관리한다. /META-INF/persistence.xml 클래스 패스 경로에 있다면, 별도의 설정 없이 JPA가 인식한다.
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
<persistence-unit name="jpabook">
<properties>
<!-- 필수 속성 -->
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.id.new_generator_mappings" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create"/>
<!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
</properties>
</persistence-unit>
</persistence>
<persistence-unit name="jpabook">
JPA는 영속성 유닛이라는 것부터 시작하는데 일반적으로 연결할 데이터베이스당 하나의 영속성 유닛을 등록한다.name
속성으로 고유한 이름을 부여한다.<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
데이터베이스 방언 설정데이터베이스 방언이란?
SQL표준을 지키지 않거나, 특정 데이터베이스만의 고유한 기능. Hibernate를 포함한 대부분의 JPA 구현체 에서는 특정 데이터베이스에 종속되지 않게 하기 위해 다양한 데이터베이스 방언 클래스를 제공한다.
어플리케이션 개발
package jpabook.start;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
// 엔티티 매니저 팩토리 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
// 엔티티 매니저 생성
EntityManager em = emf.createEntityManager();
// 트랜잭션 획득
EntityTransaction tx = em.getTransaction();
try {
tx.begin(); // 트랜잭션 시작
logic(em); // 비지니스 로직 실행
tx.commit(); // 트랜잭션 커밋
} catch (Exception e) {
tx.rollback(); // 트랜잭션 롤백
} finally {
em.close(); // 엔티티 매니저 종료
}
emf.close(); // 엔티티 매니저 팩토리 종료
}
public static void logic(EntityManager em) {
String id = "id1";
Member member = new Member();
member.setId(id);
member.setUsername("지한");
member.setAge(2);
//등록
em.persist(member);
//수정
member.setAge(20);
//한 건 조회
Member findMember = em.find(Member.class, id);
System.out.println("findMember=" + findMember.getUsername() + ", age=" + findMember.getAge());
//목록 조회
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
System.out.println("members.size=" + members.size());
//삭제
em.remove(member);
}
}
엔티티 매니저 설정
-
EntityManagerFactory 생성
persistence.xml의 설정 정보를 사용해 EntityManagerFactory를 생성한다.EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
에서 META-INF/persistence.xml에서 이름이jpabook
인 영속성 유닛을 찾아서 EntityManagerFactory를 생성한다. 이때 JPA를 동작시키키 위한 기반 객체 생성, 그리고 구현체에 따라서 DB 커넥션 풀도 생성하므로 생성하는 비용이 아주 크다. 따라서 EntityManagerFactory는 어플리케이션에 따라서 딱 한번만 생성하고 공유해야 한다. -
EntityManager 생성
EntityManager em = emf.createEntityManager();
에서 EntityManager를 생성한다. JPA의 대부분 기능은 EntityManager가 제공하고(등록, 수정, 삭제, 조회 등), 내부에서 데이터소스(데이터베이스 커넥션)을 유지하면서 데이터베이스와 통신한다. EntityManager는 데이터베이스 커넥션과 밀접한 관계가 있으므로 스레드간에 공유하거나 재사용하면 안된다. -
종료
사용이 끝난 EntityManager, 그리고 EntityManagerFactory는 다음과 같이 종료해야 한다.
em.close(); // 엔티티 매니저 종료
emf.close(); // 엔티티 매니저 팩토리 종료
트랜잭션 관리
- JPA 사용 시, 항상 트랜잭션 안에서 데이터를 변경해야 한다. 트랜잭션 API는
EntityTransaction tx = em.getTransaction();
처럼 받아오며, 정상 동작시 커밋(commit), 예외 발생시 롤백(rollback) 한다.
비지니스 로직
- 등록
String id = "id1";
Member member = new Member();
member.setId(id);
member.setUsername("지한");
member.setAge(2);
em.persist(member);
Member 엔티티를 생성하고, em.persist(member)
를 실행하게 되면 JPA는 매핑 정보를 분석해 위의 SQL을 만들어 SQL에 전달한다.
- 수정
member.setAge(20);
JPA는 값을 추적하는 기증을 갖추고 있으므로, setter로 값만 바꾸어줘도 UPDATE SQL을 생성해서 데이터에비스에 값을 변경한다.
- 삭제
em.remove(20);
remove() 메소드 사용 시, JPA는 DELETE SQL을 생성해서 실행한다.
- 한 건 조회
Member findMember = em.find(Member.class, id);
find() 메소드는 조회할 엔티티 타입과 @Id
로 엔티티 하나를 조회 할 수 있다. 그리고 조회한 결과 값으로 엔티티를 생성해서 반환한다.
JPQL
- JPA는 객체를 중심으로 개발하므로 검색을 할 때에도 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.
- 엔티티를 검색하려면 모든 데이터를 엔티티로 변경한 다음 검색해야 하는데, 말이 안된다.
- JPQL(Java Persistence Query Language)라는 쿼리 언어로 해결한다.
JPQL은 엔티티 객체(클래스와 필드)를 대상으로 쿼리한다.
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
- 여기서의 Member는 MEMBER 테이블이 아닌, Member 객체를 뜻한다.
- 자세한것은 10장에서.
Reference
- 자바 ORM 표준 JPA 프로그래밍 (김영한)
Author And Source
이 문제에 관하여(2. JPA 시작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@yuyun0124/JPA-스터디-2장
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Author And Source
이 문제에 관하여(2. JPA 시작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yuyun0124/JPA-스터디-2장저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)