JPA Entity Definition and Lifecycle Hook - TheOpenCloudEngine/uEngine-cloud GitHub Wiki

JPA ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์„ค๋ช…

๋ ˆํผ๋Ÿฐ์Šค ์ฐธ๊ณ  : http://arahansa.github.io/docs_spring/jpa.html

์ด๋ฒˆ์žฅ์€ Gearing up the MSA ์—์„œ ์ƒ์„ฑํ•˜์˜€๋˜ ์ฝ”๋“œ์— JPA ๋ถ€๋ถ„์„ ์ข€๋” ์ž์„ธํžˆ ์„ค๋ช… ํ•˜๊ณ ์ž ํ•œ๋‹ค.

์šฐ์„  Course ๋ผ๋Š” Entity ํด๋ ˆ์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ณด์ž

src/Course.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Course {
    @Id
    @GeneratedValue
    Long id;
    String title;
    int duration;
    String description;
    int maxEnrollment;
    int minEnrollment;
}

์ด ํด๋ ˆ์Šค๋Š” @Entity ๋ผ๊ณ  ๋ช…์‹œ๋ฅผ ํ•˜์˜€๋‹ค.
import ๋ฅผ ํ• ์ ์— javax ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์€ java์˜ ํ‘œ์ค€์œผ๋กœ ์ •์˜ ๋˜์–ด์žˆ๋‹ค๋Š” ๋œป์ด๋‹ค.
JPA๋ฅผ ์ œ๊ณตํ•˜๋Š” provider ๋Š” hibernate ๋„ ์žˆ๊ณ , eclipse link ๊ฐ™์€ ๊ฒƒ๋„ ์žˆ๋‹ค.
์ด๋•Œ ํ‘œ์ค€์œผ๋กœ ์ œ๊ณต๋˜์žˆ๋Š” libary๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด provider๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ๋„ ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด์ œ getter, setter ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฃผ๋Š”๋ฐ, ๋ณ€๊ฒฝํ•˜๋ฉด ์•ˆ๋˜๋Š” ๊ฐ’์ธ id๋Š” ์ œ์™ธํ•˜๊ณ  ๋งŒ๋“ค์–ด ์ค€๋‹ค.
java ์—์„œ getter, setter ๋Š” ๊ฒฝ๊ณ„๊ฐ’์„ ์„ค์ •ํ•˜์—ฌ ์ฃผ๋Š” ์—ญํ• ์ด๋‹ค.
member ๋ณ€์ˆ˜๋“ค์€ private ๊ฐ’ ์œผ๋กœ ์ฃผ๊ณ  getter, setter ๋กœ public ์„ ์ฃผ์–ด์„œ ์–ด๋Š๊ณณ์—์„œ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€๋ฅผ ํŒŒ์•…ํ• ์ˆ˜ ์žˆ๋‹ค.
์ด๋ ‡๊ฒŒ ์„ค์ •์„ ํ•ด์•ผ ๋ฐฉ์–ด์ ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

@GeneratedValue ๋Š” ์•„์ด๋””์— ์‹œ์Šคํ…œ์—์„œ ์ƒ์„ฑ๋˜๋Š” ์ผ๋ จ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.

@PrePersist, @PreUpdate

    @PrePersist
    @PreUpdate
    public void validation(){
        if( minEnrollment < 10 ){
            throw new IllegalArgumentException("์ˆ˜๊ฐ•์ƒ์€ 10๋ช… ์ด์ƒ์ด์–ด ํ•ฉ๋‹ˆ๋‹ค.");
        }
    }

@PrePersist ์–ด๋…ธํ…Œ์ด์…˜์€ insert ๋˜๊ธฐ ์ „์— ํ•ด๋‹น ๋กœ์ง์„ ์‹คํ–‰ ํ•˜๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.
JPA framework ์™€ REST ๋Š” BCI(Byte Code Instrumentation) ๋ผ๋Š” ๊ฐ•๋ ฅํ•œ libary๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ getter, setter ๋ฅผ ๊ฒฝ์œ ํ•˜์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š”๋‹ค. ํ•œ๋งˆ๋””๋กœ getter์— ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ๋„ฃ์–ด๋ดค์ž ์ธ์‹์ด ์•ˆ๋œ๋‹ค๋Š” ๋œป์ด๋‹ค.
@PreUpdate ๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋ ๋•Œ๋งˆ๋‹ค ์ฒดํฌ๋ฅผ ํ•˜์—ฌ ํ•ด๋‹น ๋กœ์ง์„ ์‹คํ–‰ ํ•˜๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.
@PreRemove ๋Š” ๊ฐ’์ด ์ง€์›Œ์งˆ๋•Œ ์ฒดํฌ๋ฅผ ํ•œ๋‹ค.
์ด๋Ÿฐ์‹์œผ๋กœ Lifecycle์„ ๋ชจ๋‘ ์ฒดํฌํ•  ์ˆ˜ ์žˆ๋‹ค.

@PostPersist

    @PostPersist
    public void greeting(){
        // ๊ด‘๊ณ ์ด๋ฉ”์ผ ๋ฐœ์†ก --> 1๋ฒˆ ๋ฐฉ๋ฒ•
        // ๊ณผ์ • ๋“ฑ๋ก์— ๋Œ€ํ•œ ์ด๋ฒคํŠธ publish --> 2๋ฒˆ ๋ฐฉ๋ฒ•
        System.out.println("๊ณผ์ •์ด ๋“ฑ๋ก๋จ " + this.getTitle());
    }

@PostPersist ์–ด๋…ธํ…Œ์ด์…˜์€ ์„ฑ๊ณต์ ์œผ๋กœ ๋“ฑ๋ก์ด ๋˜๋ฉด ๊ทธ ํ›„ ์ผ์„ ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
1๋ฒˆ ๋ฐฉ๋ฒ•์ฒ˜๋Ÿผ ๋ฐ”๋กœ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ์ž‘์„ฑ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ง์ ‘ ์—ฌ๊ธฐ์—์„œ ํ•ด๋‹น microservice๋ฅผ ์ฐพ์•„์„œ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค, 2๋ฒˆ ๋ฐฉ๋ฒ•์ฒ˜๋Ÿผ kafka๊ฐ™์€ message๋ฅผ ์•Œ๋ ค์ฃผ๊ณ , ๊ฑฐ๊ธฐ์— ์•Œ์•„์„œ ๋ฐ˜์‘ํ•ด ๋ผ๊ณ  ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ด ํ›จ์”ฌ ์ข‹๋‹ค.
์™œ๋ƒํ•˜๋ฉด microservice์˜ ๊ฐฏ์ˆ˜๊ฐ€ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์ด๋Ÿฌํ•œ Anotation์„ ํ†ตํ•˜์—ฌ Event์— ๋ฐ˜์‘ ํ• ์ˆ˜ ์žˆ๋Š” JPA๊ฐ€ ์žˆ๊ธฐ์— ์ „์ฒด ์•„ํ‚คํƒ์ณ๊ฐ€ ๊ฐ„๋‹จํ•ด์ง€๊ณ ,
์ด๊ฒƒ์€ 'microservice๋“ค์ด ๋ฐฑ๊ทธ๋ผ์šด์—์„œ ๋Œ๊ณ  ์žˆ์ง€๋งŒ, ๋ชจ๋‘ ์—ฐ๊ฒฐ ๋  ์ˆ˜ ์žˆ๋‹ค' ๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€ ํ•˜๊ณ , ํ•ด๋‹น console๋กœ ๋“ค์–ด๊ฐ€์„œ httpie๋กœ http localhost:8080 ์„ ํ˜ธ์ถœํ•ด ๋ณด์ž.
๋ฐฉ๊ธˆ ๋งŒ๋“ค์—ˆ๋˜ Course๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š๋Š”๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ,
์ด๋Š” Entity๋งŒ ๋งŒ๋“ค์—ˆ๊ณ , Repository๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•„์„œ Rest๋ฅผ ์•„์ง ์‚ฌ์šฉ ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ด๋‹ค.

src/CourseRepository.java

์ด์ œ Reopsitory๋ผ๋Š” Interface๋ฅผ ๋งŒ๋“ค ์ฐจ๋ก€์ด๋‹ค. Interface๋Š” ๊ตฌํ˜„์ฒด๋ฅผ ์ฑ„์›Œ ๋‹ฌ๋ผ๊ณ  ํ•˜๋Š” ์š”์ฒญ์ด๋‹ค.
๋„ค์ด๋ฐ ๊ทœ์น™์€ ๊ผญ ์ง€ํ‚ฌ ํ•„์š”๊ฐ€ ์—†์ง€๋งŒ, ์ฝ”๋”ฉ์‹œ Entity์™€ ๊ฐ™์€ package์— ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ ,
Entity๋’ค์— Repository๋ผ๋Š” ๋ช…๋ช…์„ ํ•˜์—ฌ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

public interface CourseRepository extends PagingAndSortingRepository<Course, Long> {
}

PagingAndSortingRepository ๋Š” ํŽ˜์ด์ง• ๊ธฐ๋Šฅ์„ ๋‹ด๊ณ  ์žˆ๋Š” Repository์ด๋‹ค
๋ ˆํŒŒ์ง€ํ† ๋ฆฌ์˜ ์ƒˆ๋กœ์šด ์œ ํ˜•์„ ๋งŒ๋“ค๊ณ  ์‹ถ์„๋•Œ๋Š” ํ•ด๋‹น Repository๋ฅผ extendsํ•ด์„œ ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
interface ์˜ ๊ตฌํ˜„์ฒด๋Š” ์—†์ง€๋งŒ Repository ์ƒ์„ฑ์‹œ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ runtime์— ์‹ค์ œ ์›Œํ‚นํ•˜๋Š” sql๋ฌธ์„ ์ƒ์„ฑํ•˜๊ณ  ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๋Š” ๊ฒƒ์„ generate ํ•ด์ค€๋‹ค

logic Test

์ด์ œ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•˜์—ฌ Lifecycle์ด ์ •์ƒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•ด ๋ด…๋‹ˆ๋‹ค.
์ฝ˜์†”์ฐฝ์„ ์—ฐ ํ›„์— mvn spring-boot:run ์œผ๋กœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ run ํ•ฉ๋‹ˆ๋‹ค.

## Course๊ฐ€ Rest๋กœ ๋“ฑ๋ก๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
$ http localhost:8080
{
    "_links": {
        "courses": {
            "href": "http://localhost:8080/courses{?page,size,sort}",
            "templated": true
        },
        "profile": {
            "href": "http://localhost:8080/profile"
        }
    }
}
## ์ •์ƒ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ
$ http localhost:8080/courses title="software modeling lecture" duration=5 maxEnrollment=5 minEnrollment=10
## @PrePersist ์— ์˜ํ•˜์—ฌ throw new IllegalArgumentException("์ˆ˜๊ฐ•์ƒ์€ 10๋ช… ์ด์ƒ์ด์–ด ํ•ฉ๋‹ˆ๋‹ค."); ๋ฐœ์ƒ
$ http localhost:8080/courses title="software modeling lecture" duration=5 maxEnrollment=5 minEnrollment=1
## @PostPersist ์— ์˜ํ•˜์—ฌ  greeting() ๋ฉ”์„œ๋“œ ์‹คํ–‰๋จ
$ http PATCH localhost:8080/courses/1 description="์„ค๋ช…"
โš ๏ธ **GitHub.com Fallback** โš ๏ธ