스프링 핵심 원리 - 기본편 - 인프런
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 초급 프레임워크 및 라이브러리 웹 개발 서버 개발 Back-End Spring 객체지향 온
www.inflearn.com
강의를 들으며 생각 정리 + "자바 ORM 표준 JPA 프로그래밍" 책 참고
JPA의 이론적인 부분도 중요하지만, 무엇보다 실제 동작하는 코드를 간단히 작성하여 JPA를 이해해보자.
Hello JPA - 프로젝트 생성
설정
- IntelliJ IDEA 2020.3.1 x64(Ultimate), JAVA 8
- Maven project(라이브러리 관리 기능과 빌드 기능 제공)
- h2 데이터베이스 1.4.199
라이브러리 추가 - pom.xml
라이브러리는 메이븐을 사용해서 관리한다. 메이븐은 간단히 얘기해서 라이브러리를 관리해주는 도구인데 pom.xml에 사용할 라이브러리를 적어주면 라이브러리를 자동으로 내려받아서 관리해준다.
<?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>ex1-hello-jpa</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<!-- JPA 하이버네이트 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.3.10.Final</version>
</dependency>
<!-- H2 데이터베이스 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
</dependency>
</dependencies>
</project>
JPA 구현체로 하이버네이트 5.3.10을 사용하고 H2 데이터베이스 1.4.199를 사용한다.
(나중에 스프링과 JPA를 같이 사용한다면 스프링부트와 하이버네이트의 버전을 잘 맞춰서 생성해야 한다.)
persistence.xml
JPA는 META-INF/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">
<persistence-unit name="hello">
<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.hbm2ddl.auto" value="create" />-->
</properties>
</persistence-unit>
</persistence>
살펴보면
<persistence-unit name="hello">
JPA의 영속성 유닛(EntityManagerFactory)에는 고유 이름을 부여해야 하는데 이때 name을 부여한다.
<!-- 필수 속성 -->
<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"/>
필수 속성에는 javax.persistence로 시작하는 JPA 표준 속성과 hibernate로 시작하는 하이버네이트 고유 속성이 있다. 특히 하이버네이트 속성에서 dialect(방언)가 중요하다. JPA는 특정 데이터베이스에 종속적이지 않은 기술이다. 따라서 다른 데이터베이스로 손쉽게 교체할 수 있어야 한다. 그런데 각 데이터베이스가 제공하는 SQL 문법과 함수는 비슷해도 조금씩 다르다는 문제점이 있기 때문에 이러한 각 데이터베이스만의 고유한 기능(방언)을 제공하기 위해 위와 같은 방언 클래스들을 제공한다. 하이버네이트는 H2, 오라클, MySQL 등의 다양한 방언을 제공한다.
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
하이버네이트 전용 속성은 위와 같다.
- show_sql : 실행한 SQL(쿼리)을 출력한다.
- format_sql : 실행한 SQL을 출력할 때 보기 쉽게 정렬한다.
- use_sql_comments : 쿼리를 출력할 때 주석도 함께 출력한다.
Hello JPA - 애플리케이션 개발
먼저 객체를 하나 만들어 본다.
@Entity
public class Member {
@Id
private Long id;
private String name;
public Member(){
}
public Member(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity는 JPA가 관리할 객체를 뜻하며, @Id는 데이터베이스 PK와 매핑한다는 뜻이다.
그리고 JPA는 기본 생성자를 요구하기 때문에 만약 인자가 있는 생성자가 있다면 따로 기본 생성자를 명시해주어야 한다.
추가로 getter, setter를 선언한다.
JPA의 구동방식은 다음과 같다.
이에 맞춰 다음 코드를 작성한다.(JpaMain.java)
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
Member member = new Member();
member.setId(1L);
member.setName("Han");
em.persist(member);
tx.commit();
} catch(Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
코드는 크게 3부분으로 나눌 수 있다.
- 엔티티 매니저 설정
- 트랜잭션 관리
- 비즈니스 로직
엔티티 매니저 설정
JPA를 시작하려면 우선 persistence.xml의 설정 정보를 사용해서 엔티티 매니저 팩토리를 생성해야 한다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용해야 한다.
엔티티 매니저 팩토리에서 엔티티 매니저를 생성한다.
EntityManager em = emf.createEntityManager();
트랜잭션 관리
엔티티 매니저를 사용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회할 수 있다. 엔티티 매니저는 트랜잭션(고객 요청)당 생성, 사용하고 버린다. (JPA의 모든 데이터 변경은 트랜잭션 안에서 실행한다.)
EntityTransaction tx = em.getTransaction();
tx.begin();
// 등록/수정/삭제/조회
...
tx.commit()
특히, 엔티티 매니저는 데이터베이스 커넥션과 밀접한 관계가 있으므로 스레드 간에 공유하거나 재사용하면 안 된다.
마지막으로 사용이 끝난 엔티티 매니저는 반드시 종료해야 한다. 애플리케이션을 종료할 때 엔티티 매니저 팩토리도 종료해야 한다.
em.close();
...
emf.close();
비즈니스 로직
비즈니스 로직은 크게 4가지가 있다.
- 등록
- 수정
- 삭제
- 조회
등록
em.persist(member)
단순히 객체 필드에 원하는 값을 넣고 persist하면 된다. 그럼 JPA는 객체 엔티티에 매핑 정보(어노테이션)를 분석해서 커밋시 insert 쿼리를 DB에 전달한다.
수정
수정은 신기하게도 setter를 사용하면 DB에까지 영향을 줄 수 있다. 이 역시 커밋 시 기존 객체 정보에 대해 수정된 사항이 있으면 update 쿼리를 DB에 전달하기 때문이다.
삭제
동일한 로직으로 진행된다.(em.remove(member))
조회
한 건을 조회할 때는 간단하다.
Member findMember = em.find(Member.class, id);
find() 메서드는 조회할 엔티티 타입과 @Id(PK)로 엔티티 하나를 조회할 수 있다. 이 때, select 쿼리를 DB에 전달한다.
그러나 하나 이상의 회원 목록을 일정 조건으로 조회하는 경우가 있다.
JPA는 객체를 중심으로 개발하지만 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하다. 즉 sql을 사용해야 하는데, JPA는 sql을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다. 데이터베이스 테이블을 대상으로 쿼리하는 SQL과 달리 JPQL은 객체를 대상으로 쿼리하는 객체 지향 SQL이기 때문에 객체 지향 프로그래밍과 잘 맞고 DB dialect를 변경해도 그에 맞게 잘 번역해준다. 다음은 여러 객체를 조회하는 JPQL의 예시이다.
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
※ 정리
JPA를 사용하기 위한 개발 환경을 설정하고 JPA를 사용해서 객체 하나를 테이브렝 등록/수정/삭제/조회하는 간단한 애플리케이션을 만들어보았다. JPA가 반복적인 SQL을 알아서 처리해준 덕분에 코드량이 상당히 많이 줄어들었다.
'java > jpa' 카테고리의 다른 글
[JPA] 다양한 연관관계 매핑 (0) | 2021.01.27 |
---|---|
[JPA] 연관관계 매핑 기초 (0) | 2021.01.26 |
[JPA] 엔티티 매핑 (0) | 2021.01.22 |
[JPA] 영속성 관리 - 내부 동작 방식 (0) | 2021.01.21 |
[JPA] JPA 소개 (0) | 2021.01.21 |