๐Ÿ”‘ ๊ธฐ๋ณธ ํ‚ค(PK) ์ƒ์„ฑ ์ „๋žต

์ดˆ์ฝ”์นฉยท2023๋…„ 2์›” 21์ผ
1

spring

๋ชฉ๋ก ๋ณด๊ธฐ
3/4
post-thumbnail

๊ธฐ๋ณธ ํ‚ค ๋งคํ•‘

Entity์˜ ๊ธฐ๋ณธ ํ‚ค๋ฅผ ๋งคํ•‘ํ•  ๋•Œ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    @Id
    @GeneratedValue

๊ธฐ๋ณธํ‚ค(PK)๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” @Id ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ๊ธฐ๋ณธํ‚ค๋กœ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. @Id๋งŒ์œผ๋กœ๋„ ๊ธฐ๋ณธํ‚ค๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋น„์ฆˆ๋‹ˆ์ฆˆ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ธฐ๋ณธํ‚ค๋ฅผ ์„ค์ •ํ•ด์•ผํ•  ๋–„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ณธํ‚ค ๊ฐ’์— ๋Œ€ํ•œ ์ƒ์„ฑ ์ „๋žต์„ @GeneratedValue ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@GeneratedValue ์–ด๋…ธํ…Œ์ด์…˜์˜ GenerationType์„ ํ™•์ธํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ๋„ค ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ๊ฐ GenerationType์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ  ์–ด๋–ค ์‹์œผ๋กœ id๋ฅผ ์„ค์ •ํ•˜๋Š”์ง€ ์‹ค์ œ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

๊ธฐ๋ณธ ์„ค์ •

๊ธฐ๋ณธ ํ‚ค ์ƒ์„ฑ ์ „๋žต์„ ์ง€์› ๊ณต๊ณ (Recruitment) Entity์™€ ์ง€์›์ž(Applicant) Entity์˜ ์˜ˆ์‹œ๋กœ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Recruitment Entity

@Entity
@Getter
@NoArgsConstructor
public class Recruitment {
    @Id
    @GeneratedValue
    @Column(name = "recruitment_id")
    private Long id;

    @Column(name = "recruitment_name")
    private String recruitment_name;

    @OneToMany(mappedBy = "recruitment",
    	cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Applicant> userList = new ArrayList<>();
}

Applicant Entity

@Entity
@Getter
@NoArgsConstructor
public class Applicant {
    @Id
    @GeneratedValue
    @Column(name = "applicant_id")
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String email;

    @Column(nullable = false)
    private String phone_number;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(nullable = false)
    private Recruitment recruitment;
}

application.yml

spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/test;MODE=MYSQL
    username: sa
    password:
    driver-class-name: org.h2.Driver

  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  jpa:
    hibernate:
      ddl-auto: create-drop

๊ธฐ๋ณธ ํ‚ค ์ƒ์„ฑ ์ „๋žต

IDENTITY

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)

์ง€์†์„ฑ ๊ณต๊ธ‰์ž๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ID ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์—”ํ‹ฐํ‹ฐ์— ๊ธฐ๋ณธ ํ‚ค๋ฅผ ํ• ๋‹นํ•ด์•ผ ํ•จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ํ‚ค ์ƒ์„ฑ์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์œ„์ž„ํ•˜๋Š” ์ „๋žต์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  id ๊ฐ’์„ 1 ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค.

JPA๋Š” commit(flush) ์‹œ์ ์—์„œ ์ฟผ๋ฆฌ๋“ค์„ DB๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ AUTO_INCREMENT๋Š” Insert ์‹œ ๊ธฐ๋ณธํ‚ค ๊ฐ’์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. AUTO_INCREMENT ์‚ฌ์šฉ ์‹œ commit์„ ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธํ‚ค ๊ฐ’์„ ์•Œ ์ˆ˜ ์—†๊ธฐ์— ์˜์†์„ฑ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. AUTO_INCREMNT๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜ˆ์™ธ์ ์œผ๋กœ persist ์‹œ์ ์— ๋ฐ”๋กœ DB๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ „์†กํ•ด PK ๊ฐ’ ์ƒ์„ฑ ํ›„ ๊ฐ์ฒด์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

SEQUENCE

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)

์ง€์†์„ฑ ๊ณต๊ธ‰์ž๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œํ€€์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—”ํ‹ฐํ‹ฐ์— ๊ธฐ๋ณธ ํ‚ค๋ฅผ ํ• ๋‹นํ•ด์•ผ ํ•จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค Sequence Object๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ id๋ฅผ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. ์œ ์ผํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œํ€€์Šค๊ฐ€ ๋ชจ๋“  ํ…Œ์ด๋ธ”์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฐ์†์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค!

Sequence๋ฅผ ์กฐํšŒํ•˜๋Ÿฌ pk ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค. ํ•˜์ง€๋งŒ, initialValue ์™€ allocationSize ๋ฅผ ์กฐ์ •ํ•จ์œผ๋กœ์จ ๊ณง๋ฐ”๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— INSERT ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ๋ผ๊ฐ€์ง€ ์•Š๊ณ , ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์Œ“์—ฌ์žˆ๋‹ค๊ฐ€ ํŠธ๋žœ์žญ์…˜ commit ํ•˜๋Š” ์‹œ์ ์— INSERT ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ๋ผ๊ฐ„๋‹ค

๊ทธ๋ ‡๋‹ค๋ฉด SEQUENCE ์ „๋žต์€ ํ…Œ์ด๋ธ”๋ณ„ ์ˆœ์ฐจ์ ์ธ id๋ฅผ ๋ถ€์—ฌ ๋ชป ํ•˜๋‚˜์š”?

๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค! ํ…Œ์ด๋ธ”๋งˆ๋‹ค DB Sequence๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” @SequenceGenerator๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Sequence Object๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Entity
@Getter
@NoArgsConstructor
@SequenceGenerator(
        name = "APPLICANT_PK_GENERATOR",
        sequenceName = "APPLICANT_PK_SEQUENCE"
)
public class Applicant {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
            generator="APPLICANT_PK_GENERATOR")
    @Column(name = "applicant_id")
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String email;

    @Column(nullable = false)
    private String phone_number;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(nullable = false)
    private Recruitment recruitment;
}

id๊ฐ€ ํ…Œ์ด๋ธ” ์ˆœ์„œ๋Œ€๋กœ ๋ถ€์—ฌ๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ‘

TABLE

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)

๊ณ ์œ ์„ฑ์„ ๋ณด์žฅํ•˜๋ ค๋ฉด ์ง€์†์„ฑ ๊ณต๊ธ‰์ž๊ฐ€ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์—ฌ ์—”ํ‹ฐํ‹ฐ์— ๊ธฐ๋ณธ ํ‚ค๋ฅผ ํ• ๋‹นํ•ด์•ผ ํ•จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ํ‚ค Table์„ ์ƒ์„ฑํ•˜์—ฌ id๋ฅผ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค.

Hibernate Sequences

HIBERNATE_SEQUENCES ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!

ํ…Œ์ด๋ธ”์˜ ์นผ๋Ÿผ์„ ํ™•์ธํ•ด๋ณด๋‹ˆ SEQUENCE_NAME๊ณผ NEXT_VAL์„ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์นผ๋Ÿผ๋ช…์„ ํ†ตํ•ด ํ…Œ์ด๋ธ” ๋ณ„๋กœ id๊ฐ’์ด ์ƒ์„ฑ๋จ์— ๋”ฐ๋ผ id๊ฐ’์„ ์ˆœ์„œ๋Œ€๋กœ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์„ฑ๋œ ํ…Œ์ด๋ธ”์ž…๋‹ˆ๋‹ค.

์ƒ์„ฑ๋œ Applicant์˜ ์ˆ˜๊ฐ€ 6๋ช…์ด๋ฏ€๋กœ NEXT_VAL๋กœ 6์„ ์ €์žฅํ•˜๊ณ  ๋‹ค์Œ Applicant๊ฐ€ ์ƒ์„ฑ๋  ๊ฒฝ์šฐ 7์„ ๋ถ€์—ฌํ•˜๊ณ  ๊ฐ’์„ 7๋กœ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

Custom Index Table

๊ฐ ํ…Œ์ด๋ธ”๋งˆ๋‹ค Index Table์„ ์„ค์ •ํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Entity
@Getter
@TableGenerator(
        name = "APPLICANT_PK_GENERATOR",
        table = "APPLICANT_PK_SEQUENCE"
)
@NoArgsConstructor
public class Applicant {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE,
        generator = "APPLICANT_PK_GENERATOR")
    @Column(name = "applicant_id")
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String email;

    @Column(nullable = false)
    private String phone_number;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(nullable = false)
    private Recruitment recruitment;
}

AUTO

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)

์ง€์†์„ฑ ๊ณต๊ธ‰์ž๊ฐ€ ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ํ•ฉํ•œ ์ „๋žต์„ ์„ ํƒํ•ด์•ผ ํ•จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. AUTO ์ƒ์„ฑ ์ „๋žต์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฆฌ์†Œ์Šค๊ฐ€ ์กด์žฌํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค๊ณ  ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณต๊ธ‰์—…์ฒด๋Š” ์Šคํ‚ค๋งˆ ์ƒ์„ฑ์„ ์ง€์›ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋Ÿฐํƒ€์ž„์— ์Šคํ‚ค๋งˆ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ์ด๋Ÿฌํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋ฌธ์„œ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์„ค์ • ๊ฐ’์— ๋”ฐ๋ผ ์ž๋™(Auto)์œผ๋กœ ์ „๋žต์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฉ์–ธ์— ๋”ฐ๋ผ ์œ„์˜ ์„ธ ๊ฐ€์ง€ ์ „๋žต ์ค‘ ํ•˜๋‚˜๋กœ ์ง€์ •๋ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก ์€?

ํŠน๋ณ„ํžˆ id๊ฐ’์„ ์„ค์ •ํ•  ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ฉด ๋ฌด๋‚œํ•˜๊ฒŒ AUTO๋กœ ์„ค์ •ํ•ฉ์‹œ๋‹ค.


Reference

https://www.inflearn.com/course/ORM-JPA-Basic#

https://gmlwjd9405.github.io/2019/08/12/primary-key-mapping.html

profile
์ดˆ์ฝ”์นฉ์ฒ˜๋Ÿผ ๋‹ฌ์ฝคํ•œ ์ฝ”๋“œ๋ฅผ ์งœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€