๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Spring/Spring Quick Start

JPA ํ”„๋กœ์ ํŠธ

 

Spring Quick Start(์ฑ…)์˜ Day5 class04~05 ์‹ค์Šต์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๊ธฐ๋กํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

์‹ค์Šตํ•œ ์ฝ”๋“œ์˜ ๋งํฌ์ž…๋‹ˆ๋‹ค.


JPA๋ž€?

ORM ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์— ๋Œ€ํ•œ ํ‘œ์ค€ํ™” ์ž‘์—…์˜ ๊ฒฐ๊ณผ๊ฐ€ JPA์ด๋‹ค.

JPA(Java Persistence API)๋Š” ๋ชจ๋“  ORM ๊ตฌํ˜„์ฒด(ORM ํ”„๋ ˆ์ž„์›Œํฌ)๋“ค์˜ ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

JDBC๋Š” Oracle, Mysql, H2 ๋“ฑ ํŠน์ • DBMS์— ์ข…์†๋˜์ง€ ์•Š๋Š” DB ์—ฐ๋™ ๊ตฌํ˜„์„ ์ง€์›ํ•œ๋‹ค.

์ด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ JPA API(javax.persistence)๋ฅผ ์ด์šฉํ•˜๋ฉด ๊ฐœ๋ฐœ ๋‹น์‹œ์—๋Š” Hibernate๋ฅผ ORM ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ์‹ค์ œ ์„œ๋น„์Šค๊ฐ€ ์‹œ์ž‘๋  ๋•Œ๋Š” TopLink๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.


===== JPA ํ”„๋กœ์ ํŠธ ์ž‘์„ฑ๋ฐฉ๋ฒ• =====

1. maven ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

2. persistence.xml ํŒŒ์ผ์ด ์ƒ์„ฑ

project structure > facet > JPA ์ถ”๊ฐ€ ํ›„ + ๋ฒ„ํŠผ ๋ˆŒ๋Ÿฌ์„œ persistence.xml ํ™•์ธ.

persistence.xml ํŒŒ์ผ์ด ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋กœ์ ํŠธํด๋”/META-INF/persistence.xml

3. pom.xml ํŒŒ์ผ์— JPA ๊ด€๋ จ ์˜์กด์„ฑ ์ถ”๊ฐ€

        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
        <!-- JPA, ํ•˜์ด๋ฒ„๋„ค์ดํŠธ -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>5.1.0.Final</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>

4. Board ํด๋ž˜์Šค ์ž‘์„ฑํ•˜๊ธฐ

JPA Entity ์ƒ์„ฑ ๊ธฐ๋Šฅ์ด intelliJ์—๋Š” ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์œผ๋‚˜

package com.springbook.biz.board;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
 * Entity implementation class for Entity: Board
 *
 */
@Entity
@Table(name = "BOARD")
public class Board {
	@Id
	@GeneratedValue
	private int seq;
	private String title;
	private String writer;
	private String content;
	@Temporal(TemporalType.DATE)
	private Date regDate = new Date();
	private int cnt;

	// Getter/Setter/toString ๋ฉ”์†Œ๋“œ
}

์–ด๋…ธํ…Œ์ด์…˜์˜ ์˜๋ฏธ

์–ด๋…ธํ…Œ์ด์…˜

์˜๋ฏธ

@Entity

@Entity๊ฐ€ ์„ค์ •๋œ ํด๋ž˜์Šค๋ฅผ ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ผ๊ณ  ํ•˜๋ฉฐ, @Entity๊ฐ€ ๋ถ™์€ ํด๋ž˜์Šค๋Š” ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘๋œ๋‹ค.

@Table

์—”ํ‹ฐํ‹ฐ์™€ ๊ด€๋ จ๋œ ํ…Œ์ด๋ธ”์„ ๋งคํ•‘ํ•œ๋‹ค. name ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ BOARD ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘ํ–ˆ๋Š”๋ฐ ์ƒ๋žตํ•˜๋ฉด ํด๋ž˜์Šค ์ด๋ฆ„์ด ํ…Œ์ด๋ธ” ์ด๋ฆ„๊ณผ ๋งคํ•‘๋œ๋‹ค. name, catalog, schema, uniqueConstraints ๋“ฑ ๋‹ค์–‘ํ•˜ ์†์„ฑ์ด ์žˆ๋‹ค.

@Id

์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์˜ ํ•„์ˆ˜ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ์„œ, ํŠน์ • ๋ณ€์ˆ˜๋ฅผ ํ…Œ์ด๋ธ”์˜ ๊ธฐ๋ณธ ํ‚ค์™€ ๋งคํ•‘ํ•œ๋‹ค. @Id ๊ฐ€ ์—†๋Š” ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋Š” JPA๊ฐ€ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•œ๋‹ค.

@Column

์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์˜ ๋ณ€์ˆ˜ ์ด๋ฆ„๊ณผ table์˜ column์ด๋ฆ„์ด ๋‹ค๋ฅผ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. name, nullable=false ๋“ฑ์˜ ์†์„ฑ๋“ค์ด ์žˆ๋‹ค.

@GeneratedValue

@Id๊ฐ€ ์„ ์–ธ๋œ ํ•„๋“œ์— ๊ธฐ๋ณธ ํ‚ค๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜์—ฌ ํ• ๋‹นํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ๋‹ค์–‘ํ•œ ์˜ต์…˜์ด ์žˆ์ง€๋งŒ @GeneratedValue๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋”ฐ๋ผ์„œ ์ž๋™์œผ๋กœ ๊ฒฐ์ •๋œ๋‹ค.

@Transient

์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค ๋‚ด์˜ ํŠน์ • ๋ณ€์ˆ˜๋ฅผ ์˜์† ํ•„๋“œ์—์„œ ์ œ์™ธํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

@Temporal

๋‚ ์งœ ํƒ€์ž…์˜ ๋ณ€์ˆ˜์— ์„ ์–ธํ•˜์—ฌ ๋‚ ์งœ ํƒ€์ž…์„ ๋งคํ•‘ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. TemporalType์˜ DATE, TIME, TIMESTAMP ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.

5. persistence.xml ํŒŒ์ผ ์ž‘์„ฑํ•˜๊ธฐ

persistence.xml ์€ JPA์—์„œ ๋ฉ”์ธ ํ™˜๊ฒฝ์„ค์ • ํŒŒ์ผ์ด๋‹ค.

META-INF ํด๋” ์•„๋ž˜์— ์žˆ์œผ๋ฉด JPA๊ฐ€ ์ธ์‹ํ•œ๋‹ค.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
	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_1.xsd">
	<persistence-unit name="JPAProject">
		<class>com.springbook.biz.board.Board</class>
		<properties>
			<!-- DB ์ปค๋„ฅ์…˜ -->
			<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
			<property name="javax.persistence.jdbc.user" value="jueun" />
			<property name="javax.persistence.jdbc.password" value="jueun" />
			<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/springquickstart?serverTimezone=Asia/Seoul&amp;useSSL=false&amp;allowPublicKeyRetrieval=true" />
			<!-- Dialect ํด๋ž˜์Šค ์„ค์ • -->
			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
			<!-- JPA ๊ตฌํ˜„์ฒด ๊ด€๋ จ ์†์„ฑ ์„ค์ • -->
			<property name="hibernate.show_sql" value="true" />
			<property name="hibernate.format_sql" value="true" />
			<property name="hibernate.use_sql_comments" value="false" />
			<property name="hibernate.id.new_generator_mappings" value="true" />
			<property name="hibernate.hbm2ddl.auto" value="create" />
		</properties>
	</persistence-unit>
</persistence>

<persistance>: ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ

<persistence-unit>: ์˜์†์„ฑ ์œ ๋‹› ์„ค์ •. ์˜์†์„ฑ ์œ ๋‹›์€ ์—ฐ๋™ํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‹น ํ•˜๋‚˜์˜ ์˜์†์„ฑ ์œ ๋‹›์„ ์‚ฌ์šฉํ•œ๋‹ค.

<class>: ์˜์†์„ฑ ์œ ๋‹› ์„ค์ •์—์„œ ๊ฐ€์žฅ ๋จผ์ € Entity class๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.

<properties>

<!-- DB ์ปค๋„ฅ์…˜ -->

Entity class์˜ properties๋ฅผ ์„ค์ •ํ•˜๋Š”๋ฐ ๋จผ์ € DB ์ปค๋„ฅ์…˜์„ ์„ค์ •ํ–ˆ๋‹ค.

<!-- Dialect ํด๋ž˜์Šค ์„ค์ • -->

JPA๋Š” ์ตœ์ ํ™”๋œ SQL์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด DBMS๋งˆ๋‹ค ๋‹ค๋ฅธ Dialect ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์ด๋ฅผ ์„ค์ •ํ–ˆ๋‹ค.

<!-- JPA ๊ตฌํ˜„์ฒด ๊ด€๋ จ ์†์„ฑ ์„ค์ • -->

์†์„ฑ

์˜๋ฏธ

hibernate.show_sql

์ƒ์„ฑ๋œ SQL์„ ์ฝ˜์†”์— ์ถœ๋ ฅํ•œ๋‹ค.

hibernate.format_sql

SQL์„ ์ถœ๋ ฅํ•  ๋•Œ, ์ผ์ •ํ•œ ํฌ๋งท์œผ๋กœ ๋ณด๊ธฐ ์ข‹๊ฒŒ ์ถœ๋ ฅํ•œ๋‹ค.

shibernate.use_sql_comments

SQL์— ํฌํ•จ๋œ ์ฃผ์„๋„ ๊ฐ™์ด ์ถœ๋ ฅํ•œ๋‹ค.

hibernate.id.new_generator_mappings

์ƒˆ๋กœ์šด ํ‚ค ์ƒ์„ฑ ์ „๋žต์„ ์‚ฌ์šฉํ•œ๋‹ค.

hibernate.hbm2ddl.auto

ํ…Œ์ด๋ธ” ์ƒ์„ฑ์ด๋‚˜ ์ˆ˜์ •, ์‚ญ์ œ ๊ฐ™์€ DDL ๊ตฌ๋ฌธ์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ• ์ง€๋ฅผ

6. ํด๋ผ์ด์–ธํŠธ ํ”„๋กœ๊ทธ๋žจ

ํด๋ผ์ด์–ธํŠธ ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•ด๋ณด์ž.

ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊ธฐ์–ตํ•˜์ž!

package com.springbook.biz.board;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class BoardServiceClient {
	public static void main(String[] args) {
		// EntityManagerFactory ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ EntityManager ๊ฐ์ฒด ์ƒ์„ฑ
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPAProject");
        EntityManager em = emf.createEntityManager();
		// EntityManager๋ฅผ ํ†ตํ•ด Transaction ๊ฐ์ฒด ์ƒ์„ฑ
		EntityTransaction tx = em.getTransaction(); // ํŠธ๋žœ์žญ์…˜ ์ œ์–ด
		try {
			// Transaction ์‹œ์ž‘
			tx.begin();
			Board board = new Board();
			board.setTitle("JPA ์ œ๋ชฉ");
			board.setWriter("๊ด€๋ฆฌ์ž");
			board.setContent("JPA ๊ธ€ ๋“ฑ๋ก ์ž˜ ๋˜๋„ค์š”.");

			// ๊ธ€ ๋“ฑ๋ก
			em.persist(board);
            
			// ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ
			String jpql = "select b from Board b order by b.seq desc";
			List<Board> boardList = em.createQuery(jpql, Board.class).getResultList();
			for (Board brd : boardList) {
				System.out.println("---> " + brd.toString());
			}
			// Transaction commit
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			// Transaction rollback
			tx.rollback();
		} finally {
			em.close();
		}
		emf.close();
	}
}

 

*EntityManager์˜ CRUD ๋ฉ”์†Œ๋“œ

EntityManager๊ฐ์ฒด๊ฐ€ ์ œ๊ณตํ•˜๋Š” CRUD ๊ธฐ๋Šฅ์˜ ๋ฉ”์†Œ๋“œ์ด๋‹ค.

๋ฉ”์†Œ๋“œ

๊ธฐ๋Šฅ ์„ค๋ช…

persist(Object entity)

INSERT

merge(Object entity)

UPDATE

remove(Object entity)

DELETE

find(Object entity)

SELECTE ONE

createQuery(Object entity)

SELECT LIST

*JPQL

๊ธ€ ๋ชฉ๋ก์„ ์กฐํšŒํ•  ๋•Œ, JPQL(Java Persistence Query Language)๋ผ๋Š” JPA ๊ณ ์œ ์˜ ์ฟผ๋ฆฌ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

JPQL์„ ์ž‘์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•˜๋ฉด, ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ๊ฐ™์€ JPA ๊ตฌํ˜„์ฒด๊ฐ€ JPQL์„ ์—ฐ๋™๋˜๋Š” DBMS์— ๋งž๊ฒŒ ์ ์ ˆํ•œ SELECT ๋ช…๋ น์–ด๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋œ๋‹ค.

7. ์‹คํ–‰๊ฒฐ๊ณผ

์ž˜ ๋œ ๋‹ค !