(1) H2 데이터베이스 설치
H2 데이터베이스 설치 방법
- http://www.h2database.com 접속
- All Platforms 또는 Platform-Independent Zip 내려받고 압축 풀기
- 압축 푼 곳에서 bin/h2.sh 실행
- H2 데이터베이스를 서버 모드로 실행
- H2 데이터베이스를 서버 모드로 실행한 후에 http://localhost:8082 접속
이때, 포트번호 8082가 이미 사용 중일 경우 해당 포트번호의 프로세스를 종료 후 시도해야 에러가 발생하지 않는다.
- jdbc:h2:tcp://~/DB이름 으로 생성
- jdbc:h2:tcp://localhost/~/DB이름 으로 접속
입력항목 | 정보 |
드라이버 클래스 | org.h2.Driver |
JDBC URL | dbc:h2:tcp://localhost/~/test |
사용자명 | sa |
비밀번호 | 입력하지 않음 |
(2) 객체 매핑 시작
회원 테이블 생성
CREATE TABLE MEMBER (
ID LONG AUTO_INCREMENT NOT NULL, -- 아이디(기본키)
NAME VARCHAR(255), -- 이름
AGE INTEGER NOT NULL, -- 나이
PRIMARY KEY (ID)
)
회원 클래스 생성
public class Member {
private Long id;
private String username;
private Integer age;
public Long getId() {
return id;
}
public void setId(Long 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;
}
}
매핑 정보
매핑 정보 | 회원 객체 | 회원 테이블 |
클래스와 테이블 | Member | MEMBER |
기본 키 | id | ID |
필드와 컬럼 | username | NAME |
필드와 컬럼 | age | AGE |
매핑 정보가 포함된 회원 클래스
import javax.persistence.*;
@Entity
@Table(name="MEMBER")
public class Member {
@Id
@Column(name = "ID")
private Long id;
@Column(name = "NAME")
private String username;
private Integer age;
public Long getId() {
return id;
}
public void setId(Long 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에게 알려준다.
@Entity
가 사용된 클래스를 엔티티 클래스 라고 한다.
@Table
- 엔티티 클래스와 매핑할 테이블 정보를 알려준다.
name 속성
을 사용해서Member 엔티티
를MEMBER 테이블
에 매핑- 이 어노테이션을 생략하면
클래스 이름
을 그대로 테이블 이름으로 매핑
@Id
- 엔티티 클래스의 필드를 테이블의 기본 키(Primary Key)에 매핑
- 엔티티의
id 필드
를 테이블의ID 기본 키
컬럼에 매핑 @Id
가 사용된 필드를 식별자 필드 라고 한다.
@Column
- 필드를 컬럼에 매핑한다.
- name 속성을 사용해서 Member 엔티티의 username 필드를 테이블의 NAME 컬럼에 매핑
매핑 정보가 없는 필드
- 매핑 어노테이션을 생략하면 필드명을 사용해서 컬럼명으로 매핑된다.
- 필드명이 age이므로 age 컬럼으로 매핑
- 만약 대소문자를 구분하는 데이터베이스를 사용하면
@Column(name="AGE")
처럼 명시적으로 매핑해야 한다.
하이버네이트 설정 옵션
데이터베이스마다 차이점
- 데이터 타입 (가변 문자 타입 => MySQL 은
VARCHAR
, 오라클은VARCHAR2
사용) - 다른 함수명 (문자열 자르기 => SQL 표준은
SUBSTRING()
, 오라클은SUBSTR()
) - 페이징 처리 (MySQL은 LIMIT, 오라클은 ROWNUM)
Dialect(방언) : JPA에서 SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능
옵션
- hibernate.show_sql : 실행한 SQL을 출력.
- hibernate.format_sql : SQL을 보기 좋게 정렬함.
- hibernate.use_sql_comments : 쿼리 출력 시 주석도 함께 출력
- hibernate.id.new_generator_mappings : JPA 표준에 맞는 새로운 키 생성 전략을 사용함.
하이버네이트 설정
- create : Session Factory가 실행될 때 스키마를 지우고 다시 생성. 클래스패스에
import.sql
이 존재하면 찾아서 해당 SQL도 함께 실행한다. - create-drop : create와 같지만 session factory가 내려갈 때 스키마 삭제
- update : 시작 시, 도메인과 스키마를 비교하여 필요한 컬럼 추가 등의 작업을 실행. 데이터는 삭제하지 않는다.
- validate : Session factory 실행 시 스키마가 적합한지 검사함. 문제가 있으면 에외 발생
- 개발 시에는 create, 운영 시 auto 설정을 빼거나 validate 정도로 두는 것이 좋아 보인다. update로 둘 경우, 개발자들의 스키마가 마구 꼬여서 결국은 drop 해서 새로 만들어야 하는 사태가 발생한다.
(3) 어플리케이션 개발
// 시작 코드
import javax.persistence.*;
import java.util.List;
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) {
e.printStackTrace();
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 emf = Persistence.createEntityManagerFactory("jpabook")
- META-INF/persistence.xml에서 이름이 "jpabook" 인 영속성 유닛을 찾아서 엔티티 매니저 팩토리를 생성
- Persistence 클래스 사용.
- Persistence 클래스 : 엔티티 매니저 팩토리를 생성해서 JPA를 사용할 수 있게 준비.
중요
엔티티 매니저 팩토리는 어플리케이션 전체에 딱 한 번만 생성하고 공유해서 사용해야 한다.
엔티티 매니저 생성
EntityManager em = emf.createEntityManager();
- 엔티티 매니저를 사용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회할 수 있다.
- 엔티티 매니저는 데이터베이스 커넥션과 밀접한 관계가 있으므로 스레드간에 공유하거나 재사용하면 안된다.
- 엔티티 매니저를 가상의 데이터베이스로 생각할 수 있다!
종료
사용이 끝난 엔티티 매니저는 반드시 종료
em.close(); // 엔티티 매니저 종료
어플리케이션을 종료할 때 엔티티 매니저 팩토리도 종료
emf.close(); // 엔티티 매니저 팩토리 종료
트랜잭션 관리
JPA를 사용하면 항상 트랜잭션 안에서 데이터를 변경해야 한다.
트랜잭션 없이 데이터를 변경하면 예외가 발생한다.
트랜잭션을 시작하려면 엔티티 매니저에서 트랜잭션 API를 받아와야 한다.
EntityTransaction tx = em.getTransaction(); //트랜잭션 기능 획득
try {
tx.begin(); //트랜잭션 시작
logic(em); //비즈니스 로직
tx.commit();//트랜잭션 커밋
} catch (Exception e) {
tx.rollback(); //트랜잭션 롤백
}
비지니스 로직
회원 엔티티를 하나 생성한 다음 엔티티 매니저를 통해 데이터베이스에 등록, 수정, 삭제, 조회
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);
수정
em.update()
같은 메소드가 없고, 단순히 엔티티의 값만 변경한다.
=> JPA는 어떤 엔티티가 변경되었는지 추적하는 기능을 갖추고 있기 때문에 가능하다!
JPQL
하나 이상의 회원 목록을 조회하는 코드
//목록 조회
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
System.out.println("members.size=" + members.size());
문제점
검색 쿼리 사용 시 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.
그러나 테이블이 아닌 엔티티 객체를 대상으로 검색하려면 데이터베이스 모든 데이터를 어플리케이션으로 불러와 엔티티 객체로 변경해서 검색해야 함.
따라서 애플리케이션이 필요로 하는 데이터만 데이터베이스에서 불러오기 위해 검색 조건이 포함된 SQL을 사용해야 한다.
=> JPQL
(Java Persistence Query Language) 이라는 쿼리 언어를 사용하여 해결할 수 있다!
차이점
- JPQL : 엔티티 객체를 대상으로 쿼리. (클래스와 필드 대상)
- SQL : 데이터베이스 테이블을 대상으로 쿼리.
예시
select m from Member m
from Member
는 회원 엔티티 객체를 말하는 것이지MEMBER 테이블
이 아니다. => JPQL은 데이터베이스 테이블을 전혀 알지 못한다.- JPA는 JPQL을 분석하여 적절한 SQL로 만들어 데이터베이스에 질의
다음과 같이 해석된다.
SELECT M.ID, M.NAME, M.AGE FROM MEMBER M
- JPQL은 대소문자를 구분한다.
- JPQL을 사용하려면 먼저
em.createQuery(JPQL, 반환 타입)
메소드를 실행해서 쿼리 객체를 생성한 후 쿼리 객체의getResultList()
메소드를 호출하면 된다.
'Read Book > JPA 프로그래밍' 카테고리의 다른 글
6장. 다양한 연관관계 매핑 (0) | 2023.02.20 |
---|---|
5장. 연관관계 매핑 기초 (0) | 2023.02.20 |
4장. 엔티티 매핑 (0) | 2023.02.20 |
3장. 영속성 관리 (0) | 2023.02.20 |
1장. JPA 소개 (0) | 2023.02.20 |