JPA 시작하기
<?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>jpa-basic</groupId>
<artifactId>hello-jpa</artifactId>
<version>1.0.0</version>
<dependencies>
<!-- Java 11 사용 시 추가 필요 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- JPA 하이버네이트 -->
<dependency>
<groupId>org.hibernate</groupId>
<!-- hibernate core, javax.persistence 등이 담겨있다. -->
<!-- javax.persistence는 JPA 인터페이스를 가지고 있다. -->
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.1.Final</version>
</dependency>
<!-- H2 데이터베이스 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</project>
Java 8
Maven
groupId: jpa-basic
artifactId: ex1-hello-jpa
version: 1.0.0
JPA 설정하기
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<!-- JPA 이름 설정: 데이터베이스 당 하나를 부여한다. -->
<persistence-unit name="hello">
<properties>
<!-- 필수 속성: DB 접속 정보 -->
<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"/>
<!-- JPA는 특정 DB에 종속적이지 않아 hibernate 전용 옵션을 추가해줘야 한다. -->
<!-- DB마다 각자 dialect가 다르기 때문에 H2 dialect를 추가한다. -->
<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.hbm2ddl.auto" value="create" />-->
</properties>
</persistence-unit>
</persistence>
resources/META-INF/persistence.xml
persistence-unit
이름 지정
javax.persistence
JPA 표준 속성
hibernate
하이버네이트 전용 속성
dialect

JPA는 특정 DB에 종속되지 않는다.
각각의 DB가 제공하는 SQL 문법과 함수가 조금씩 다르다.
이렇게 SQL 표준을 지키지 않는 특정 DB만의 고유한 기능을 방언이라고 한다.
애플리케이션 개발
JPA 구동 방식

JPA의 Persistence
클래스가 META-INF/persistence.xml
설정 파일을 읽어서 EntityManagerFactory
라는 클래스를 생성한다. 여기서 필요할 때마다 EntityManager
를 만든다.
회원 생성
create table Member
(
id bigint not null,
name varchar(255),
primary key (id)
);
이 테이블대로 객체를 만들고 DB에서 불러와보자.
public class JpaMain {
public static void main(String[] args) {
// EntityManagerFactory는 애플리케이션 로딩 시점에 딱 하나만 만들어야 한다.
// persistence.xml에서 설정했던 'persistence-unit name' 값을 넘긴다.
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
// EntityManager를 꺼낸다.
// EntityManager는 트랜잭션마다 만들어줘야 한다.
EntityManager entityManager = entityManagerFactory.createEntityManager();
// JPA의 모든 작업은 트랜잭션 내에서 해야 적용된다.
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
try {
// 실제 동작 코드를 작성한다.
Member member = new Member();
member.setId(1L);
member.setName("helloA");
// 저장한다.
entityManager.persist(member);
// 정상적이면 커밋한다.
tx.commit();
} catch (Exception e) {
// 실패하면 롤백한다.
tx.rollback();
} finally {
// EntityManager가 내부적으로 데이터베이스 커넥션을 물고 동작하기 때문에 쓰고 나서 꼭 닫아줘야 한다.
entityManager.close();
}
// 전체 애플리케이션이 끝나면 팩토리까지 닫아준다.
entityManagerFactory.close();
}
}
Hibernate:
insert into Member(name, id) values(?, ?)
실행하면 위와 같은 쿼리가 날아간다.
회원 수정
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
try {
// 수정할 대상을 가져온다.
Member findMember = entityManager.find(Member.class, 1L);
System.out.println("id: " + findMember.getId());
System.out.println("name: " + findMember.getName());
findMember.setName("helloJPA");
// 수정한 객체를 따로 저장하지 않아도 된다.
// 데이터를 JPA를 통해 가져오면 변경 여부를 트랜잭션 커밋 시점에
// 다 체크해서 바뀐 내용에 대해 업데이트 쿼리를 만들어 날린다.
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
entityManager.close();
}
entityManagerFactory.close();
}
}
update Member set name=? where id=?
update 쿼리가 나가는 걸 확인할 수 있다.
주의할 점
EntityManagerFactory
애플리케이션 실행 시점에 하나만 생성해서 애플리케이션 전체에 걸쳐 공유한다.
EntityManager
요청이 왔을 때 썼다가 끝나면 버리는 사이클을 반복한다.
그래서 절대 스레드 간에 공유해서는 안된다. 사용하고 바로 버려야 한다.
JPA의 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.
트랜잭션을 실제 지정해본 경험이 없어도 DB 자체적으로 트랜잭션을 사용하기 때문에 적용해왔을 것이다.
JPQL
EntityManger.find()
는 가장 단순한 조회 방법이다.나이가 18살 이상인 회원
같은 쿼리는 JPQL을 사용해야 한다.
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
try {
// 일반적인 쿼리처럼 생겼지만 JPA는 테이블이 아니라
// 객체를 대상으로 쿼리를 짜기 때문에
// 여기서 Member는 테이블이 아니라 객체를 가리킨다.
List<Member> result = entityManager
.createQuery("select m from Member as m", Member.class)
// 페이지네이션을 할 수도 있다. 아래는 1번부터 10개 가져온다.
.setFirstResult(1)
.setMaxResults(10)
.getResultList();
for (Member member : result) {
System.out.println("name: " + member.getName());
}
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
entityManager.close();
}
entityManagerFactory.close();
}
}
JPA를 사용하면 Entity 객체를 중심으로 개발하게 된다.
검색 또한 테이블이 아닌 Entity 객체를 대상으로 한다.
모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하다.
필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
하지만 쿼리를 쓰면 SQL에 종속된다.
이때 객체를 대상으로 검색할 수 있게 하는 기술이 JPQL이다.
SQL과의 차이
JPQL
Entity 객체를 대상으로 쿼리
SQL
데이터베이스 테이블을 대상으로 쿼리
특징
JPA가 제공하는 SQL을 추상화한 객체 지향 쿼리 언어
한마디로 객체지향 SQL이다.
추상화했기 때문에 특정 데이터베이스에 의존하지 않는다.
SQL과 문법이 유사하다.
select, from, where, group by, having, join을 지원한다.
Last updated
Was this helpful?