일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- 백준 10815 # 백준 Java
- 이미지 업로드
- AWS
- Flask
- 도메인 주도 개발
- springboot
- validation
- 개발 프로젝트
- logout
- session
- 예외 처리
- jwt
- CustomException
- @Valid
- ec2 nginx websocket reverse proxy
- 관점 지향 프로그래밍
- 스프링부트
- presigned url
- spring boot
- fastapi
- oauth2.0
- 구글 로그인
- 소셜 로그인
- 패러다임 불일치
- OpenAI API
- spring websocket nginx 설정
- 자바 orm
- GoormIDE
- wss 연결 실패
- S3
- Today
- Total
개발세발은 안되요
[자바 ORM 표준 JPA 프로그래밍] 02 : JPA 시작 본문
2.3 라이브러리와 프로젝트 구조 JP
JPA 구현체로 하이버네이트를 사용하기 위한 핵심 라이브러리는 다음 등등이 있다.
- hibernate-core : 하이버네이트 라이브러리
- hibernate-entitymanager : 하이버네이트가 JPA 구현체로 동작하도록 JPA 표준을 구현한 라이브러리
- hibernate-jpa-2.1-api : JPA 2.1 표준 API를 모아둔 라이브러리
2.3.1 메이븐과 사용 라이브러리 관리
메이븐은 라이브러리를 관리해주는 도구인데 pom.xml에 사용할 라이브러리를 적어주면 라이브러리를 자동으로 내려받아서 관리해준다.
메이븐(Maven)
최근의 자바 애플리케이션은 메이븐 같은 도구를 사용해서 라이브러리를 관리하고 빌드하는데, 메이븐은 크게 라이브러리 관리 기능과 빌드 기능을 제공한다.
1. 라이브러리 관리 기능
자바 애플리케이션을 개발하려면 jar 파일로 된 여러 라이브러리가 필요하다. 과거에는 라이브러리를 직접 내려받아 사용했지만, 메이븐은 사용할 라이브러리 이름과 버전만 명시하면 라이브러리를 자동으로 내려받고 관리해준다.
2. 빌드 기능
과거에는 Ant를 주로 사용했지만 개발자마다 작성하는 Ant 스크립트는 조금씩 다르다. 메이븐은 애플리케이션을 빌드하는 표준화된 방법을 제공한다.
2.4 객체 매핑 시작
JPA 어노테이션
JPA 어노테이션을 사용하기 위해 javax.persistence 패키지를 import 한다.
- @Entity : 클래스를 테이블과 매핑한다고 JPA에게 알려준다. @Entity가 사용된 클래스를 엔티티 클래스라 한다.
- @Table : 엔티티 클래스에 매핑할 테이블 정보를 알려준다. 이 어노테이션을 생략하면 클래스 이름을 테이블 이름으로 매핑한다.
- @Id : 엔티티 클래스의 필드를 테이블의 기본 키(primary key)에 매핑한다. @Id 가 사용된 필드를 식별자 필드라 한다.
- @Column : 필드를 컬럼에 매핑한다.
- 매핑 정보가 없는 필드 : 매핑 어노테이션을 생략하면 필드명을 사용해서 컬럼명으로 매핑한다. 만약 대소문자를 구분하는 데이터베이스를 사용하면 명시적으로 매핑해주어야 한다.
사용 예시)
import javax.persistence.*; @Entity @Table(name="MEMBER") public class Member{ @Id @Column(namd = "ID") private String id; @Column(name = "NAME") private String username; private Integer age; ... }
2.5 persistence.xml 설정
JPA는 persistence.xml을 사용해서 필요한 설정 정보를 관리하는데, 이 설정 파일이 META-INF/persistence.xml 클래스 패스 경로에 있으면 별도의 설정 없이 JPA가 인식할 수 있다.
<persistence xmlns = "http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
설정 파일은 persistence로 시작한다. 이곳에 XML 네임스페이스와 사용할 버전을 명시한다. JPA 2.1 을 사용하려면 xmlns와 version을 명시한다.
<persistence-unit name="jpabook">
JPA 설정한 영속성 유닛(persistence-unit)이라는 것부터 시작하는데, 일반적으로 연결할 데이터베이스당 하나의 영속성 유닛을 등록한다. 영속성 유닛에는 고유한 이름을 부여해야 한다.
사용 가능한 속성들로는 다음과 같은 것들이 있다.
1. JPA 표준 속성
- javax.persistence.jdbc.driver : JDBC 드라이버
- javax.persistence.jdbc.user : 데이터베이스 접속 아이디
- javax.persistence.jdbc.password : 데이터베이스 접속 비밀번호
- javax.persistence.jdbc.url : 데이터베이스 접속 URL
2. 하이버네이트 속성
- hibernate.dialect : 데이터베이스 방언(Dialect) 설정
이름이 javax.persistence로 시작하는 속성은 JPA 표준 속성으로 특정 구현체에 종속되지 않지만, hibernate로 시작하는 속성은 하이버네이트 전용 속성이므로 하이버네이트에서만 사용할 수 있다.
2.5.1 데이터베이스 방언
JPA는 특정 데이터베이스에 종속되지 않기 때문에 다른 데이터베이스로 쉽게 교체할 수 있다. 하지만 각 데이터베이스가 제공하는 SQL 문법과 함수가 조금씩 다르다는 문제점이 있다.
1. 데이터 타입 : 가변 문자 타입으로 MySQL은 VARCHAR을, 오라클은 VARCHAR2를 사용함.
2. 다른 함수명 : 문자열을 자르는 함수로 SQL 표준은 SUBSTRING()을, 오라클은 SUBSTR()을 사용함.
3. 페이징 처리 : MySQL은 LIMIT를 사용하지만 오라클은 ROWNUM을 사용함.
이처럼 SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능을 JPA에서는 방언(Dialect)라 한다. 애플리케이션 개발자가 이런 방언들을 많이 사용하면 나중에 데이터베이스를 교체하기가 어렵기 때문에 하이버네이트를 포함한 대부분의 JPA 구현체들은 이런 문제를 해결하기 위해 다양한 데이터베이스 방언 클래스를 제공한다.
개발자는 JPA가 제공하는 표준 문법에 맞추어 JPA를 사용하면 되고, 특정 데이터베이스에 의존적인 SQL은 데이터베이스 방언이 처리해준다. 따라서 데이터베이스가 변경되어도 애플리케이션 코드를 변경할 필요 없이 데이터베이스 방언만 교체하면 된다. 데이터베이스 방언을 설정하는 방법은 JPA에 표준화되어 있지 않다.
하이버네이트가 제공하는 다양한 데이터베이스 방언
- H2 : org.hibernate.dialect.H2Dialect
- 오라클 10g : org.hibernate.dialect.Oracle10gDialect
- MySQL : org.hibernate.dialect.MySql5InnoDBDialect
2.6 애플리케이션 개발
애플리케이션을 시작하는 코드는 다음과 같다.
public class JpaMain{
public static void main(String[] args){
// [ 엔티티 매니저 팩토리 ] - 생성
EntityManager emf = Persistence.createEntityManegerFactory("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(); // [ 엔티티 매니저 팩토리 ] - 종료
}
private static void logic(EntityManager em) {...}
}
코드는 크게 3부분으로 나위어져 있다.
- 엔티티 매니저 설정
- 트랜잭션 관리
- 비즈니스 로직
2.6.1 엔티티 매니저 설정
엔티티 매니저의 생성 과정은 다음과 같다.
엔티티 매니저 팩토리 생성
JPA를 시작하기 위해 persistenc.xml의 설정 정보를 사용해 엔티티 매니저 팩토리를 생성한다. 이때 Persistence 클래스를 사용하는데, 이 클래스는 엔티티 매니저 팩토리를 생성하여 JPA를 사용할 수 있게 준비한다.
이를 통해 META-INF/persistence.xml에서 이름이 jpabook인 영속성 유닛을 찾아서 엔티티 매니저 팩토리를 생성한다. 이때 persistence.xml의 설정 정보를 읽어 JPA를 동작시키기 위한 기반 객체를 만들고 경우에 따라 커넥션 풀도 생성하기 때문에 엔티티 매니저 팩토리를 생성하는 비용은 아주 크다. 그러므로 엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용해야 한다.EntityMenagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
엔티티 매니저 생성
EntityManager em = emf.createEntityManager();
엔티티 매니저 팩토리에서 엔티티 매니저를 생성한다. JPA의 기능 대부분은 이 엔티티 매니저가 제공하는데, 대표적으로 엔티티 매니저를 사용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회할 수 있다.
종료
em.close(); // 엔티티 매니저 종료
사용이 끝난 엔티티 매니저는 반드시 종료해야 한다.
emf.close(); // 엔티티 매니저 팩토리 종료
애플리케이션을 종료할 때 엔티티 매니저 팩토리는 종료해야 한다.
2.6.2 트랜잭션 관리
JPA를 사용하면 항상 트랜잭션 안에서 데이터를 변경해야 하는데, 트랜잭션 없이 데이터를 변경하면 예외가 발생한다. 트랜잭션을 시작하기 위해서는 엔티티 매니저에서 트랜잭션 API를 받아온다.
EntityTransaction tx = em.getTransaction(); // 트랜잭션 API
try{
tx.begin(); // 트랜잭션 시작
logic(em); // 비즈니스 로직 실행
tx.commit(); // 트랜잭션 커밋
} catch(Exception e){
tx.rollback(); // 예외 발생 시 트랜잭션 롤백
}
트랜잭션 API를 이용해서 비즈니스 로직이 정상 동작하면 트랜잭션을 커밋하고, 예외가 발생하면 트랜잭션을 통해 롤백한다.
2.6.3 비즈니스 로직
비즈니스 로직은 등록, 수정, 삭제, 조회 작업이 엔티티 매니저를 통해 수행된다. 이런 점에서 엔티티 매니저는 객체를 저장하는 가상의 데이터베이스처럼 보인다.
1. 등록
String id = "id1"; Member member = new Member(); member.setId(id); member.setUsername("지한"); member.setAge(2); // 등록 em.persist(member);
엔티티를 저장하기 위해 엔티티 매니저의 persist() 메소드에 저장할 엔티티를 넘겨준다. 위의 경우 JPA는 회원 엔티티의 매핑 정보(어노테이션)을 분석해서 다음과 같은 SQL을 만들어 데이터베이스에 전달한다.INSERT INTO MEMBER (ID, NAME, AGE) VALUES ('id1', '지한', 2)
2. 수정
// 수정 member.setAge(20);
JPA는 어떤 엔티티가 변경되었는지 추적하는 기능을 가지고 있기 때문에 엔티티의 값만 변경하면 UPDATE SQL을 생성해서 데이터베이스에 전달해준다.
3. 삭제
em.remove(member);
엔티티를 삭제하려면 엔티티 매니저의 remove() 메소드에 삭제하려는 엔티티를 넘겨준다.
4. 한 건 조회
Member member = em.find(Member.class, id);
find() 메소드는 조회할 엔티티 타입과 @Id로 데이터베이스 테이블의 기본 키와 매핑한 식별자 값으로 엔티티 하나를 조회하는 가장 단순한 조회 메소드다. 이 메소드를 호출하면 SELECT SQL을 생성해서 데이터베이스에 결과를 조회하고, 조회한 결과 값으로 엔티티를 생성해서 반환한다.
2.6.4 JPQL
JPA를 사용하면 애플리케이션 개발자는 엔티티 객체를 중심으로 개발하고 데이터베이스에 대한 처리는 JPA에 맡겨야 한다. 검색 쿼리에서도 마찮가지로 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.
하지만 테이블이 아닌 엔티티 객체를 대상으로 검색하려면 데이터베이스의 모든 데이터를 애플리케이션으로 불러와서 엔티티 객채로 변경한 다음 검색해야 하는데, 이는 사실상 불가능하다. 애플리케이션이 필요한 데이터만 데이터베이스에서 불러오려면 결국 검색 조건이 포함된 SQL을 사용해야 하는데, JPA는 JPQL(Java Persistence Query Language)이라는 쿼리 언어로 이런 문제를 해결한다.
JPA는 SQL을 추상화한 JPQL 이라는 객체지향 쿼리 언어를 제공한다. JPQL은 SQL과 문법이 거의 유사해서 SELECT, FROM, GROUP BY, HAVING, JOIN 등을 사용할 수 있는데, 차이점은 다음과 같다.
- JPQL은 엔티티 객체를 대상으로 쿼리한다. 즉 클래스와 필드를 대상으로 쿼리한다.
- SQL은 데이터베이스 테이블을 대상으로 쿼리한다.
- JPQL은 대소문자를 명확하게 구분하지만 SQL은 관례상 대소문자를 구분하지 않고 사용하는 경우가 많다.
// 목록 조회 TypedQuery<Member> query = em.createQuery("select m from Member m", Member.class); List<Member> members = query.getResultList();
위의 예시에서 select m from Member m 이 JPQL이다. 여기서 from Member은 회우너 엔티티를 의미한다.(테이블이 아니다.) JPQL은 테이블을 전혀 알지 못한다.
JPQL을 사용하려면 먼저 em.createQuery(JPQL, 반환 타입) 메소드를 실행하여 쿼리 객체를 생성한 후 쿼리 객체의 getResultList() 메소드를 호출한다.
'책 > 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
[자바ORM표준JPA프로그래밍] 03장 : 영속성 관리 (1) | 2024.09.13 |
---|---|
[자바 ORM표준 JPA 프로그래밍] 01장 : JPA 소개 (0) | 2024.08.30 |