이 장에서는 jpa를 이용하여 테이블을 CRUD하는 jpa 어플리케이션을 만들어본다.
📍2.1 이클립스 설치와 프로젝트 불러오기
IDE로 이미 인텔리제이가 깔려있어서 그걸 사용하기로 했다...ㅎㅎ
📍2.2 H2 데이터베이스 설치
h2도 이미 깔려있었고 Member 테이블만 만들어주었다.
📍2.3 라이브러리와 프로젝트 구조
jpa 구현체로 하이버네이트를 사용하기 위한 핵심 라이브러리는 아래와 같다
1. hibernate-core : 하이버네이트 라이브러리
2. hibernate-entitymanager : 하이버네이트가 JPA 구현체로 동작하도록 JPA 표준을 구현한 라이브러리
3. hibernate-jpa-2.1-api : JPA 2.1 표준 API를 모아둔 라이브러리
🍥 2.3.1 메이븐과 사용 라이브러리 관리
메이븐은 라이브러리를 관리해주는 도구인데 pom.xml에 사용할 라이브러리를 적어주면 라이브러리를 자동으로 내려받아서 관리해준다.
groupId, artifactId, version을 적으면 라이브러를 메이븐 공식 저장소에 내려받아 라이브러리에 추가해준다.
여기서는 JPA, 하이버네이트 / H2 데이터베이스를 내려받는다.
📍2.4 객체 매핑 시작
먼저 데이터베이스에 회원테이블을 만들어두기!!
그리고 회원 클래스도 만들어주자
package com.example.jpastart;
public class Member {
private String id;
private String username;
private Integer age;
// Getter, Setter
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;}
}
매핑 정보 | 회원 객체 | 회원 테이블 |
---|---|---|
클래스와 테이블 | Member | MEMBER |
기본 키 | id | ID |
필드와 컬럼 | username | NAME |
필드와 컬럼 | age | AGE |
앞으로 이렇게 객체와 테이블을 매핑 진행할 것이다.
그러려면 매칭 어노테이션을 추가해야한다.
@Entity
@Table(name="MEMBER")
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name="NAME")
private String username;
private Integer age;
.
.
.
}
일단은 어노테이션을 정리해보겠다! 😎
@Entity
이 클래스를 테이블과 매핑한다고 JPA에게 알려주는 역할
@Entity가 사용된 클래스를 엔티티 클래스라고 부름
*@Table
*엔티티 클래스에 매핑한 테이블 정보를 알려주는 역할
여기서는 name 속성을 사용해서 Member 엔티티를 MEMBER 테이블에 매핑함
( @Table 생략 시, 클래스 이름을 테이블 이름으로 매핑 )
*@Column
*필드를 컬럼에 매핑함
name 속성을 사용해 Member 엔티티의 username 필드를 MEMBER 테이블의 NAME 컬럼에 매핑
매핑 정보가 없는 필드
매핑 정보가 없는 필드의 경우에는 필드명을 사용해서 컬럼명으로 매핑함
필드명이 age면 age 컬럼과 매핑
📍2.4 persistence.xml 설정
JPA는 persistence.xml을 사용해서 필요한 설정 정보를 관리한다.
<?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" />-->
</properties>
</persistence-unit>
</persistence>
해당 내용을 살펴보자!
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
설정 파일은 persistence로 시작하는데 여기서는 xml 네임스페이스와 사용할 버전을 지정해준다.
<persistence-unit name="jpabook">
JPA 설정은 영속성 유닛에서 시작하고 연결한 데이터베이스 당 하나의 영속성 유닛을 등록한다. 그리고 영속성 유닛에는 이름을 부여해야 한다.
JPA 표준 속성
javax.persistence.jdbc.driver : JDBC 드라이버
javax.persistence.jdbc.user : 데이터베이스 접속 아이디
javax.persitence.jdbc.password : 데이터베이스 접속 비밀번호
javax.persistence.jdbc.url : 데이터베이스 접속 URL
하이버네이트 속성
hibernate.dialect : 데이터베이스 방언 설정
🍥 2.5.1 데이터베이스 방언
JPA는 특정 데이터베이스에 종속적이지 않아서 손쉽게 데이터베이스를 교체할 수 있다. 그렇지만 각 데이터베이스가 제공하는 SQL 문법이 조금씩 다르다.
데이터 타입 : 가변 문자 타입 ( MySQL -> VARCHAR / Oracle -> VARCHAR2 )
다른 함수명 : 문자열 자르는 함수 ( MySQL -> SUBSTRING() / Oracle => SUBSTR() )
페이징 처리 : MySQㅣ -> LIMIT / Oracle -> ROWNUM
**방언**
SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능
JPA를 사용하게 되면 데이터베이스가 변경되어도 데이터베이스 방언만 교체하면 된다.
📍2.6 애플리케이션 개발
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) {
...
}
위 코드에서는 엔티티 매니저 설정, 트랜잭션 관리, 비즈니스 로직으로 구성되어 있다.
🍥 엔티티 매니저 설정
엔티티 매니저 팩토리 설정
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
JPA 시작을 위해서 엔티티 매니저 팩토리를 생성해주어야 한다.
위의 코드에서는 이름이 jpabook인 영속 유닛을 찾아 엔티티 매니저 팩토리를 생성하고 이때 persistence.xml의 설정 정보를 읽어 객체를 만든다. 이때 비용이 크기 때문에 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용해야한다!!
엔티티 매니저 설정
EntityManager em = emf.createEntityManager();
엔티티 매니저를 생성하는데 엔티티 매니저를 사용해서 엔티티를 DB에 CRUD할 수 있다!
그리고 엔티티 매니저는 DB 커넥션과 밀접한 관계가 있으므로 스레드 간에 공유하거나 재사용하면 안된다고 한다!!
종료
엔티티 매니저 사용이 끝나면 종료하고 팩토리도 종료해야 한다
🍥 2.6.2 트랙잭션 관리
JPA 사용시에는 트랜잭션 안에 데이터를 변경해야 한다.
만약 트랜잭션 없이 데이터를 변경하면 예외가 발생해야 하고 트랜잭션을 시작하려면 엔티티 메니지에서 트랙잭션 AP를 받아와야 한다.
그리고 이를 통해 비즈니스 로직이 정상적으로 작동하면 커밋, 예외 발생 시 롤백한다.
🍥 2.6.3 비즈니스 로직
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);
}
해당 코드에서 CRUD가 엔티티 매니저를 통해 수행되고 있다.
등록
엔티티 매니저의 persiste()에 엔티티를 넘겨준다. 그러면 JPA는 매핑 정보를 분석하여 'INSERT INTO MEMBER (ID, NAME, AGE) VALUES ('id1, '지한', 2)'를 데이터베이스에 전달한다.
수정
엔티티를 수정한 후에 수정 내용을 반영하지 않아도 JPA는 어떤 엔티티가 변경되었는지 추적하는 기능을 갖춘다는 점이 포인트다!!
삭제
em.remove();에 삭제하려는 엔티티를 넘겨주고 JPA는 DELETE SQL을 생성하여 실행한다.
한 건 조회
find() 메서드를 통해 엔티티 타입과 @Id로 엔티티 하나를 조회한다. 역시 JPA가 SELECT SQL을 생성해 조회해주고 반환한다.
🍥 2.6.4 JPQL
여기서는 createQuery를 통해 SQL을 사용하고 있다.
엔티티 객체를 대상으로 검색하려면 검색 조건이 포함된 SQL을 사용해야 하고 JPA는 JPQL라는 쿼리 언어를 사용하게 된다. 그리고 SQL과 문법이 거의 유사하다!!
그러나 JPQL은 엔티티 객체를 대상으로 쿼리(클래스와 필드를 기준으로)
SQL은 데이터베이스 테이블을 대상으로 쿼리한다!
즉 위의 JPQL에서는 from Member는 멤버 테이블이 아닌 엔티티 객체를 의미한다
여기서는 순수 JPA를 사용해서 간단한 CRUD를 해보았는데 나는 지금까지 Spring Data JPA만 사용해왔기 때문에 신기했다. 엔티티매니저를 직접 설정해주는 부분이 신기했다...!
그리고 Spring Data JPA가 더 쉬운데 왜 내가 순수 JPA를 배워야하지? 실무에서는 뭘 사용하는 거지? 이런 생각이 들었는데 아래의 게시물의 답변을 보고 음.. 그렇구나~~ 라고 생각할 수 있었다!
순수 JPA 기반 리포지토리와 스프링 데이터 기반 리포지토리 비교 - 인프런 | 커뮤니티 질문&답변
누구나 함께하는 인프런 커뮤니티. 모르면 묻고, 해답을 찾아보세요.
www.inflearn.com
'BE > 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
[JPA STUDY] 5. 연관관계 매핑 기초 (0) | 2025.04.06 |
---|---|
[JPA STUDY] 4장. 엔티티 매핑 (0) | 2025.03.30 |
[JPA STUDY] 03. 영속성 관리 (0) | 2025.03.22 |
[ JPA STUDY ] 1장. JPA 소개 (0) | 2025.03.15 |