JPA 시작
2. JPA 시작
2.1 IntelliJ 설치와 프로젝트 설정하기
-
책에서는 이클립스를 사용하였으나 IntelliJ가 더 편하다고 생각되어 IntelliJ를 사용하여 프로젝트 설정하는 방법을 정리하였다.
- IntelliJ 설치
- IntelliJ
- 커뮤니티 버전이 무료이므로 커뮤니티 버전으로 다운받는다.
- 프로젝트 설정
- start.spring.io
- Dependencies에 H2 Database와 Spring Data JPA를 검색하여 추가한다.
- 아래 화면과 같이 설정한 후 Generate 버튼을 클릭하여 다운받는다.
- 다운받은 zip 파일 압축을 풀고 IntelliJ에서 압축 푼 폴더안의 build.gradle을 Open 한다. Open As Project를 선택한다.
2.2 H2 데이터베이스 설치
- H2 Database
- OS에 맞는 버전을 설치해준다.
- Mac 기준으로 bin 폴더의 h2.sh를 실행하면 데이터베이스가 실행되면서 웹브라우저에 아래와 같이 접속창이 뜬다.
- 최초 1회는 데이터베이스 생성을 위해 아래 주소와 같이 설정하여 연결을 클릭한다.
- 이후부터는 아래와 같이 localhost로 접속한다.
2.3 라이브러리와 프로젝트 구조
- 책에서는 라이브러리 관리 도구로 메이븐을 사용하지만, Gradle을 사용하도록 한다.
- Gradle은 build.gradle 파일에 필요한 라이브러리를 추가하면 된다.
- 필요한 라이브러리는 MVN Repository 에서 찾으면 된다.
- 예를 들어, Spring JDBC를 추가할 경우 아래와 같이 찾은 뒤, 텍스트 박스의 내용을 build.gradle 파일의 dependencies 에 추가한다. 그리고 우측 상단의 코끼리 아이콘이 생기면 클릭하여 Load 해준다.
- 예제를 실행하는데 필요한 라이브러리는 com.h2database 와 org.springframework.boot:spring-boot-starter-data-jpa 두 개면 충분한 것 같다.
2.4 객체 매핑 시작
- H2 데이터베이스에서 아래와 같이 SQL을 실행해서 회원 테이블을 만든다.
- Member 클래스를 만들고 매핑 어노테이션을 추가한다.
- @Entity
- 클래스를 테이블과 매핑한다고 알려준다.
- @Entitiy가 사용된 클래스를 엔티티 클래스라고 한다.
- @Table
- 테이블 정보를 알려준다. name 속성으로 테이블 이름을 설정한다.
- @Id
- 엔티티 클래스의 필드를 테이블의 기본 키(PK)에 매핑한다.
- @Column
- 필드를 컬럼에 매핑한다. name 속성으로 테이블의 컬럼이름을 설정한다.
- 매핑 정보가 없는 필드
- 필드명을 사용해서 컬럼명으로 매핑한다.
@Entity
@Table(name = "member")
public class Member {
@Id
@Column(name="id")
private String id;
@Column(name = "name")
private String username;
private Integer age;
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;
}
}
2.5 persistence.xml 설정
- JPA는 persistence.xml을 사용해서 필요한 설정 정보를 관리한다.
- META-INF/persistence.xml 클래스 패스 경로에 있으면 JPA가 자동으로 인식한다.
- resources 밑에 META-INF 디렉토리를 생성한다. (IntelliJ 기준)
- META-INF 디렉토리에 persistence.xml 파일을 생성한다.
- 데이터베이스당 하나의 영속성 유닛을 등록한다.
- 엔티티 클래스를 class 태그를 이용하여 등록한다.
- hibernate.hbm2ddl.auto 속성을 이용하면 데이터베이스 테이블도 자동으로 생성해준다.
- hibernate.dialect 속성은 데이터베이스 방언을 설정한다.
- java.persistence 속성은 JPA 표준 속성으로 특정 구현체에 종속되지 않고, hibernate 속성은 하이버네이트 전용 속성이다.
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
version="2.1">
<persistence-unit name="jpabook">
<class>jpabook.start.Member</class>
<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/~/jpabook"/>
<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.user_sql_comments" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>
2.5.1 데이터베이스 방언
- 데이터베이스 벤더별로 제공하는 SQL 문법과 함수가 조금씩 다르다.
- 가변문자타입 사용시 MySQL은 VARCHAR, 오라클은 VARCHAR2를 사용한다.
- 페이징처리시 MySQL은 LIMIT, 오라클은 ROWNUM을 사용한다.
- 이처럼 SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능을 방언이라고 한다.
- JPA 구현체에서 이런 문제를 해결하기 위해 데이터베이스 방언 클래스를 제공한다.
- 개발자는 JPA가 제공하는 표준 문법에 맞추어 JPA를 사용하고, 특정 데이터베이스에 의존적인 SQL은 데이터베이스 방언이 처리해준다.
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) {
tx.rollback();
}
finally {
em.close();
}
emf.close();
}
private 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);
}
}
2.6.1 엔티티 매니저 설정
- 엔티티 매니저 팩토리 생성
-
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
- createEntityManagerFactory 메소드의 인자로 META-INF/persistence.xml 에서 설정한 영속성 유닛의 이름을 전달한다.
- 엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용해야 한다.
-
- 엔티티 매니저 생성
-
EntityManager em = emf.createEntityManager();
- JPA의 기능 대부분은 엔티티 매니저가 제공한다.
- 엔티티 매니저를 사용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회할 수 있다.
- 엔티티 매니저는 스레드간에 공유하거나 재사용하면 안된다.
-
- 종료
- 사용이 끝난 엔티티 매니저는 반드시 종료해야 한다.
-
em.close();
- 애플리케이션을 종료할 때 엔티티 매니저 팩토리도 종료해야 한다.
-
emf.close();
2.6.2 트랜잭션 관리
- JPA 사용시 항상 트랜잭션 안에서 데이터를 변경해야 한다.
- 트랜잭션을 사용하면 비즈니스 로직이 정상 동작하면 커밋하고, 비즈니스 로직에서 예외가 발생하면 롤백한다.
2.6.3 비즈니스 로직
- 등록
- 등록은 persist 메소드에 저장할 엔티티 오브젝트를 전달하면 된다.
-
insert into member (id, name, age) values ('id1', '지한', 2)
- 수정
- 수정은 단순히 엔티티의 오브젝트의 값을 변경하면 된다.
- JPA가 변경내용을 감지하여 추적한다.
-
update member set age=20, name='지한' where id='id1'
- 삭제
- 삭제는 remove 메소드에 삭제하려는 엔티티 오브젝트를 전달하면 된다.
-
delete from member where id='id1'
- 한 건 조회
- 한 건 조회는 find 메소드에 조회할 엔티티 타입과 기본 키로 매핑한 식별자 값을 전달하면 된다.
-
select * from member where id='id1'
2.6.4 JPQL
- 등록, 수정, 삭제, 한 건 조회 등은 JPA를 사용하여 SQL 사용 없이 처리할 수 있다.
- 검색 쿼리는 JPQL 이라는 쿼리 언어로 처리해야 한다.
- JPQL은 엔티티 객체를 대상으로 쿼리한다. 즉, 클래스와 필드를 대상으로 쿼리한다.
- SQL은 데이터베이스 테이블을 대상으로 쿼리한다.
-
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
- “select m from Member m” 이 JPQL이고 from Member는 테이블이 아니라 Member 엔티티 객체를 가리킨다.
Leave a comment