๐Ÿ๏ธ Spring/JPA

(์ œ ๊ถ๊ธˆ์ฆ ํ’€ ์šฉ๋„๋กœ ์ •๋ฆฌํ•œ๊ฑฐ๋ผ ๋ง‰ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค.) ๐Ÿง ManyToOne, OneToOne ์—ฐ๊ด€๊ด€๊ณ„ ์ผ๋ฐ˜์ ์œผ๋กœ merge ์‹œ merge๋˜๋Š” ํŠน์ • ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•ด์„œ๋งŒ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ cascade ์†์„ฑ์ด MERGE๋ผ๋ฉด merge ์‹œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋“ค๋„ left join์œผ๋กœ ์กฐํšŒํ•ด์˜ต๋‹ˆ๋‹ค. merge()๊ฐ€ ๋˜์–ด ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ๋„ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” fk ๊ฐ’์˜ ๋ณ€๊ฒฝ๋งŒ์ด ๋ฐ˜์˜๋˜์ง€๋งŒ, cascade ์†์„ฑ์ด merge๋ผ๋ฉด ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๋ณ€๊ฒฝ๋„ ํ•จ๊ป˜ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. (DB ๊ด€์ ์—์„œ ์ƒ๊ฐํ•˜๋ฉด ํŽธํ•ฉ๋‹ˆ๋‹ค) @NoArgsConstructor @Accessors(fluent = true) @Getter @Entity public class Member { @Id @GeneratedValue(strategy = Ge..
๐Ÿง ๋ฌธ์ œ ์ƒํ™ฉ @Service @Transactional @RequiredArgsConstructor public class PostService { private final PostRepository postRepository; private final MemberRepository memberRepository; public Long create(CreatePostCommand command) { Member member = memberRepository.findById(command.memberId()) .orElseThrow(NotFoundMemberException::new); Post post = command.toPost(member); Post saved = postRepository.sa..
์ด ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ๊ฑฐ์˜ 5์‹œ๊ฐ„๋™์•ˆ ๋””๋ฒ„๊น… ํ•ด์„œ ์›์ธ ์ฐพ์•„๋ƒˆ๋Š”๋ฐ, ์•Œ๊ณ ๋ณด๋‹ˆ๊นŒ 1์›” 26์ผ์ธ๊ฐ€(๋ถˆ๊ณผ ํ•œ๋‹ฌ ์ „) ํ•ด๊ฒฐ๋˜์–ด ์žˆ๋”๋ผ๊ตฌ์š”.. ๋‹ค๋งŒ ์•„์ง ์Šคํ”„๋ง๋ถ€ํŠธ jpa dependency ๋ฒ„์ „์— ๋ฐ˜์˜์ด ์•ˆ๋˜์–ด์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ๊ทธ๋ƒฅ ์Šฌํผํ•˜๋Š” ์ค‘์ž…๋‹ˆ๋‹ค. ์•„๋งˆ ๊ณง ํ•ด๊ฒฐ๋  ๊ฒƒ ๊ฐ™์€๋ฐ, ํ•ด๋‹น ์˜ค๋ฅ˜๋Š” Hibernate 6.2 ์ด์ „ ๋ฒ„์ „์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๐Ÿง ๋ฌธ์ œ ์ƒํ™ฉ ์žฌํ˜„ ์•„๋ž˜์™€ ๊ฐ™์ด 1๋Œ€ ๋‹ค ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„ One๊ณผ Many๋ฅผ ์ •์˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค. @Entity public class One { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(fetch = FetchType.LAZY, orphanRemoval =..
๐Ÿง ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ์— ๋Œ€ํ•œ UNIQUE ์ œ์•ฝ์กฐ๊ฑด ์„ค์ •ํ•˜๊ธฐ @Table์˜ uniqueConstraints ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์˜ˆ์‹œ @Table( name="ํ…Œ์ด๋ธ” ์ด๋ฆ„", uniqueConstraints={ @UniqueConstraint( name = "unique ์ œ์•ฝ์กฐ๊ฑด ์ด๋ฆ„", columnNames = { "ํฌํ•จํ•  ์ปฌ๋Ÿผ์ด๋ฆ„ 1", "ํฌํ•จํ•  ์ปฌ๋Ÿผ์ด๋ฆ„ 2" } ), } columnNames๋Š” ํ•„๋“œ๊ฐ€ ์•„๋‹Œ ์ปฌ๋Ÿผ๋ช…๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. @Table( uniqueConstraints={ @UniqueConstraint( columnNames={"column1"}) } ) @Table( uniqueConstraints = { @UniqueConstraint(name = "UniqueNumber..
๐Ÿง N + 1 ๋ฌธ์ œ N + 1 ๋ฌธ์ œ๋Š” ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์„ค์ •๋œ ์—”ํ‹ฐํ‹ฐ ์‚ฌ์ด์—์„œ ํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜์˜€์„ ๋•Œ, ์กฐํšŒ๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐœ์ˆ˜(N ๊ฐœ)๋งŒํผ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€์ ์ธ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ N + 1์—์„œ, 1์€ ํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์ฟผ๋ฆฌ์˜ ๊ฐœ์ˆ˜์ด๋ฉฐ, N์€ ์กฐํšŒ๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐœ์ˆ˜๋งŒํผ ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ ์ฟผ๋ฆฌ์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. N + 1๋ณด๋‹ค๋Š”, 1 + N์ด๋ผ ๋ถ€๋ฅด๋Š” ๊ฒƒ์ด ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šฐ๋ฉฐ, ์ •๋ฆฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ ์ฟผ๋ฆฌ(1 ๋ฒˆ) + ์กฐํšŒ๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐœ์ˆ˜(N ๊ฐœ)๋งŒํผ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ (N ๋ฒˆ) ๐Ÿง ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์„ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ๊ฒŒ์‹œ๊ธ€๊ณผ ๋Œ“๊ธ€์„ ์˜ˆ์‹œ๋กœ ์‚ฌ์šฉํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ๊ฒŒ์‹œ..
๐Ÿฅบ ์„œ๋ก  ๋„๋ฉ”์ธ ๊ณ„์ธต์˜ Repository์™€ ์˜์†์„ฑ ๊ณ„์ธต์˜ Repository๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉํ•ด๋ณด๋ ค ์‹œ๋„ํ–ˆ๋˜ ๊ณผ์ •์—์„œ, findBy*** ์‹์˜ ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ์™€, @Query๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ง์ ‘ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋“ฑ์˜ ๋ฉ”์„œ๋“œ๋Š” ์–ด๋–ค ์‹์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜๊ณ , ์–ด๋ ค์šด ๋‚ด์šฉ์€ ์•„๋‹ˆ๊ธฐ๋„ ํ•˜๊ณ  ์ƒ๊ฐํ–ˆ๋˜ ๋ฐฉ์‹ ๊ทธ๋ž˜๋„ ์ ์šฉ๋˜๊ธด ํ•˜์ง€๋งŒ, ๊ทธ๋ž˜๋„ ํ˜น์‹œ ๋„์›€ ๋˜์‹œ๋Š” ๋ถ„์ด ์žˆ์„๊นŒ๋ด ์ž‘์„ฑํ•˜๋ ค ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿง ๋„๋ฉ”์ธ ๊ณ„์ธต์˜ Repository์™€, ์˜์†์„ฑ ๊ณ„์ธต์˜ Repository ๋ถ„๋ฆฌํ•˜๊ธฐ ์ €๋Š” ์œ„ ์‚ฌ์ง„์ฒ˜๋Ÿผ ๋„๋ฉ”์ธ ๊ณ„์ธต๊ณผ ์ธํ”„๋ผ์ŠคํŠธ๋Ÿญ์ณ ๊ณ„์ธต์„ ๋‚˜๋ˆ„์—ˆ๊ณ , JpaArticleRepository๋Š” ArticleRepository๋ฅผ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค. ArticleRepository๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ƒ์†๋ฐ›์€ Jp..
๊ธฐ์กด Auditing์„ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. @EntityListeners(AuditingEntityListener.class) @MappedSuperclass public class BaseEntity { @CreatedDate @Column(updatable = false) private LocalDateTime createdDate; @LastModifiedDate private LocalDateTime lastModifiedDate; } ์œ„์˜ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” ํ•ญ์ƒ 2022-03-06T14:12:23.0023123 ๊ณผ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ์ €์žฅ๋˜์—ˆ๋Š”๋ฐ, ์ด๋ฅผ ์ข€ ๋” ๊น”๋”ํ•œ format์œผ๋กœ ๋ฐ”๊พธ๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿด ๋•Œ๋Š” @PrePersist, @PreUpdate๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ..
(https://ttl-blog.tistory.com/807)ํ•ด๋‹น ๊ธ€์—์„œ ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ, save()์˜ ์ž‘๋™ ์›๋ฆฌ์— ๋Œ€ํ•˜์—ฌ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ @GenerateValue๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‹๋ณ„์ž๋ฅผ ์ง์ ‘ ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š”, ์ด๋ฏธ ์‹๋ณ„์ž ๊ฐ’์ด ์žˆ๋Š” ์ƒํƒœ๋กœ save()๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰ ์ด ๊ฒฝ์šฐ์—๋Š” merge()๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” Persistable์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ์ธ์ง€ ํŒ๋ณ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ง์ ‘ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Persistable์˜ ์›๋ฆฌ Persistable์€ ์œ„์™€ ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. save ํ˜ธ์ถœ ์‹œ์—๋Š” SimpleJpaRepository์˜ save ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ entityInformation์€ JpaE..
๋ง ๋ž‘
'๐Ÿ๏ธ Spring/JPA' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๊ธ€ ๋ชฉ๋ก