JPA란?
[Spring] JPA(Java Persistence API)란?
JPA(Java Persistence API)란?JPA(Java persistence API)는 자바 진영에서 ORM(Object-Relational-Mapping) 기술 표준으로 사용되는 인터페이스의 모음입니다. 그 말은 즉, 실제적으로 구현된것이 아니라 구현된 클래스
h-1-y.tistory.com
개발환경
IDE : STS4
Java : 17
Framework : Springboot
Build Tool : Maven
Database : H2
H2 Database
H2는 JAVA로 작성된 관계형 데이터베이스 관리 시스템입니다. H2 데이터베이스는 설치가 간편하고, 용량이 매우 가벼우며, 웹용 콘솔(쿼리툴)을 제공하여 로컬 환경이나 테스트 환경에서 많이 쓰이는 특징이 있습니다.
H2 사용법
H2 Database Engine
H2 Database Engine Welcome to H2, the Java SQL database. The main features of H2 are: Very fast, open source, JDBC API Embedded and server modes; in-memory databases Browser based Console application Small footprint: around 2.5 MB jar file size Supp
h2database.com
해당 홈페이지에 접속하여 All Platforms를 선택하여 zip파일을 다운로드 받은 후 원하는 경로에 압축을 풀어줍니다.
H2 DB를 실행하기 위해서는 window OS의 경우에는 h2.bat 파일을 실행시켜주면 되고, macOS의 경우 터미널을 통해 /h2/bin/~ 경로
로 접근 후 ./h2.sh로 H2 DB를 실행시켜주면 됩니다.
H2 DB가 정상적으로 실행 되었다면 localhost port 번호 8082로 접근이 가능합니다.
H2 DB가 정상적으로 연결 되었다면 Database를 만들 차례입니다. 해당 아이콘을 통해 Create a new database 메뉴를 통해 Database를 생성하여 생성한 접속정보로 연결(Connect)합니다. (Database path의 앞은 . 이아닌 ~ 로 작성해줍니다.)
아래의 화면이 나온다면 H2 Database 정상적으로 연결된것 입니다. 해당 웹 콘솔을 통해 SQL 문을 사용하실 수 있습니다.
STS 프로젝트 생성
이제 STS를 사용해서 프로젝트를 생성해보겠습니다.
Maven Project를 선택하고 org.apache.maven.archetypes / maven-archetype-quickstart 를 선택해줍니다.
Group id / Artfact id / Package를 설정하고 Finish 를 눌러주면 콘솔창에 로그가 올라가며 콘솔창에 Y를 입력해주면 BUILD SUCCESS 라는 문구와 함께 프로젝트가 정상적으로 생성됩니다.
프로젝트 생성 후 resources 폴더가 보이지 않는다면, 프로젝트 우클릭 -> Properties -> Java Build Path -> Order and Export 탭에서 resources 폴더를 체크 후 Apply 해주면 정상적으로 디렉토리가 노출됩니다.
Dependency 및 Persistence 환경설정
Dependency
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</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>2.2.224</version>
</dependency>
<!-- JAXB -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
JPA를 사용하는데 필요한 hibernate와 h2 라이브러리를 dependency를 통해 추가 해줍니다.
자바 11 이상의 버전을 사용하는 경우 Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException 라는 에러가 발생하게 됩니다. 에러가 발생하는 이유는 JAXB(Java Architecture for XML Bind)라는 Java Object를 XML로 직렬화 해주거나, XML을 Java Object로 역직렬화 해주는 Java API가 자바 11 이상 버전부터는 삭제 되었기 때문입니다. 자바 11 이상을 사용하시는 분들은 jaxb-api 라이브러리를 추가해 주시면 됩니다.
Persistence
persistence.xml 설정파일의 디렉토리 위치는 /resources/META-INF/persistence.xml 입니다. 해당 위치에 파일을 생성하면 별도의 설정 없이 JPA가 자동으로 인식하게 됩니다.
<?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="1234" />
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/jpabasic" />
<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"> : 영속성 유닛(persistence-unit)은 연동할 데이터베이스당 하나씩 등록되며, 설정된 이름은 추후 EntityManagerFactory 객체에 사용됩니다.
- <property name="javax.persistence.jdbc.~" ~> : 데이터베이스의 접속정보를 설정해줍니다.
- <property name="hibernate.dialect" ~> : hibernate는 데이터베이스에 종속적이지 않습니다. dialect는 데이터베이스 방언(언어, 사투리 등)으로 해당 옵션으로 서로 다른 데이터베이스 문법, 타입 등을 알아서 처리해줍니다.
- <property name="hibernate.show_sql" value="true"> : Hibernate가 DB의 처리내용을 콘솔에 출력해줍니다.
- <property name="hibernate.format_sql" value="true"> : SQL 콘솔 로그를 가독성 있게 정렬 후 출력해줍니다.
- <property name="hibernate.use_sql_comments" value="true"> : 쉬운 디버깅을 위해 /* */ 주석을 추가해줍니다.
- <property name="hibernate.hbm2ddl.auto" value="create"> : Hibernate는 DDL을 자동으로 작성해주는 ddl-auto 옵션이 있습니다. (create, create-drop, update, vaildate, none)
간단한 JPA 실습
Entity 생성
간단한 구조의 Member Entity를 생성하여 테이블과 매핑 시켜줍니다.
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
//@Table(name = "USER") 테이블명 지정 방법
public class Member {
@Id // PK 설정
private long id;
// @Column(name = "username") 컬럼명 지정 방법
private String 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에서 테이블과 매핑할 객체는 @Entity 어노테이션을 필수로 붙여주어야 합니다.
- @Table : 데이터베이스 테이블명을 별도로 지정할 경우 @Table 어노테이션의 name 속성을 사용합니다.
- @Id : 해당 테이블의 PK(Primary key)를 설정합니다.
- @Column : 컬럼명을 별도로 지정할 경우 @Column 어노테이션의 name 속성을 사용합니다.
EntityManagerFactory, EntityManager, EntityTransaction
- EntityManagerFactory : EntityManagerFactory는 말 그대로 EntityManager를 생성하는 공장입니다. EntityManagerFactory는 애플리케이션 로딩 시점에 DB당 하나의 팩토리만 생성해야합니다.
- EntityManager : EntityManager는 Entity를 CRUD를 하는 등의 엔티티와 관련된 모든 일을 처리합니다. 클라이언트의 요청이 올때 마다 (즉, thread가 하나씩 생성될 때마다) EntityManager를 생성합니다. 엔티티메니저는 클라이언트의 요청이 들어올 때 생성했다가 요청을 수행 후 닫아야합니다. thread간 공유를 하면 안되고 트랜잭션이 수행된 후에는 반드시 닫고 DB 커넥션을 반환해야합니다.
- EntityTransaction : 데이터를 변경하는 모든 작업은 반드시 트랜잭션 안에서 이루어져야 합니다. JPA의 모든 데이터 변경은 트랜잭션 안에서 실행됩니다.
저장 - persist();
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaTest {
public static void main(String[] args) {
// EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManager는 스레드간 공유 X(사용하고 버려야 함)
EntityManager em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try {
// 등록
Member member = new Member();
member.setId(1L);
member.setName("HAN");
em.persist(member);
et.commit();
} catch (Exception e) {
et.rollback();
} finally {
em.close();
}
emf.close();
}
}
조회 - find();
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JpaTest {
public static void main(String[] args) {
// EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManager는 스레드간 공유 X(사용하고 버려야 함)
EntityManager em = emf.createEntityManager();
// 조회
Member findMember = em.find(Member.class, 1L);
System.out.println(findMember.getId());
}
}
수정 - set
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaTest {
public static void main(String[] args) {
// EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManager는 스레드간 공유 X(사용하고 버려야 함)
EntityManager em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try {
// 조회
Member findMember = em.find(Member.class, 1L);
// 수정
findMember.setName("PARK");
et.commit();
} catch (Exception e) {
et.rollback();
} finally {
em.close();
}
emf.close();
}
}
삭제 - remove();
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaTest {
public static void main(String[] args) {
// EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManager는 스레드간 공유 X(사용하고 버려야 함)
EntityManager em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try {
// 조회
Member findMember = em.find(Member.class, 1L);
// 삭제
em.remove(findMember);
et.commit();
} catch (Exception e) {
et.rollback();
} finally {
em.close();
}
emf.close();
}
}
reference
'Back-End > Spring' 카테고리의 다른 글
[Spring] JPA 기본키(Primary Key) 매핑 (1) | 2024.09.04 |
---|---|
[Spring] JPA Entity Mapping (0) | 2024.07.16 |
[Spring] JPA(Java Persistence API)란? (0) | 2024.07.09 |
[Spring] DispatcherServlet이란? (0) | 2024.06.24 |
[Spring] MVC Pattern (0) | 2024.06.24 |