๐Ÿ๏ธ Spring/JPA

์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ ๊ธฐ๋Šฅ์„ ์Šคํ”„๋ง MVC์™€ ํ•จ๊ป˜ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. http ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ Pageable ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๋Š”๋ฐ ๋‹ค์Œ์€ ๊ทธ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. @GetMapping("/members") public Page list(Pageable pageable) { Page page = memberRepository.findAll(pageable); return page; } ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ Pageable ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ํ• ๋‹น๋˜๋Š” ๊ฐ์ฒด๋Š” PageRequest(org.springframework.data.domain.PageRequest) ์ž…๋‹ˆ๋‹ค. ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ํ˜•์‹ ?page=2&size=3&sort=id,desc&sort=username,des..
์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์•„๋ฌด๋Ÿฐ ์„ค์ • ์—†์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์ „ @RestController @RequiredArgsConstructor public class MemberController { private final MemberRepository memberRepository; @GetMapping("/members/{id}") public String findMember(@PathVariable("id") Long id) { Member member = memberRepository.findById(id).get(); return member.getUsername(); } } ์‚ฌ์šฉ ํ›„ @RestController @RequiredArgsConstructor public class MemberC..
Auditing ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์„ฑ, ๋ณ€๊ฒฝํ•  ๋•Œ์˜ ์‹œ๊ฐ„๊ณผ, ๋ณ€๊ฒฝํ•œ ์‚ฌ๋žŒ์„ ์ถ”์ ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ˆœ์ˆ˜ํ•˜๊ฒŒ JPA๋งŒ ์“ด๋‹ค๋ฉด @PrePersist ๋“ฑ์˜ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•ด์„œ ๋“ฑ๋ก๋˜๋Š” ์‹œ์ ์— ์‹œ๊ฐ„๊ณผ ์‚ฌ๋žŒ ๋“ฑ์„ ์ €์žฅํ•˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์Šคํ”„๋ง Data JPA๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ด๋ฅผ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค. ์„ค์ • ์•„๋ž˜ ๋‘ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. @EnableJpaAuditing -> ์Šคํ”„๋ง ๋ถ€ํŠธ ์„ค์ • ํด๋ž˜์Šค์— ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. @EntityListeners(AuditingEntityListener.class) -> ์—”ํ‹ฐํ‹ฐ์— ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ @EntityListeners(AuditingEntityListener.class) @MappedSuperclass public cl..
์‚ฌ์šฉ์ž ์ •์˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ตฌํ˜„๋ฐฉ๋ฒ• ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์ •์˜ํ•˜๊ณ  ๊ตฌํ˜„์ฒด๋Š” ์Šคํ”„๋ง์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๊ฐ€ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ ์ด์™ธ์— ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์ด๋ฅผ ์ƒ์†๋ฐ›์•„ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž ์ •์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ JPA ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ƒ์†๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ ์ธํ„ฐํŽ˜์ด์Šค public interface MemberRepositoryCustom { List findMemberCustom(); } ์‚ฌ์šฉ์ž ์ •์˜ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ ํด๋ž˜์Šค @RequiredArgsConstructor public class MemberRepositoryImpl implements MemberRepository..
(Lock ์— ๋Œ€ํ•ด์„œ๋Š” ์ œ๊ฐ€ ์•„์ง ๊ณต๋ถ€๋ฅผ ์ž˜ ๋ชปํ•˜์—ฌ์„œ, ์ดํ›„ ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค) Data JPA์—์„œ์˜ Lock ์„ค์ • @Lock์„ ํ†ตํ•ด ๊ฐ„ํŽธํ•˜๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ์‹œ interface MemberRepository : JpaRepository { @Lock(LockModeType.PESSIMISTIC_WRITE) fun findByUsername(username: String): Member? } ์ง€์›ํ•˜๋Š” Lock์˜ ์ข…๋ฅ˜ ํ•ด๋‹น LockModeType์˜ ํŒจํ‚ค์ง€๋ฅผ ์‚ดํŽด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฆ‰ Lock์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ JPA์˜ ํ‘œ์ค€ ์ŠคํŽ™์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ @Lock์„ ํ†ตํ•ด ํ•ด๋‹น ์„ค์ •์„ ํŽธํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ๊ฒƒ์€ Data JPA์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. Reference ์‹ค์ „! ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA - ์ธํ”„..
JPA Hint JPA ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ธฐ๋Šฅ์ด ์•„๋‹Œ ์–ด๋– ํ•œ ๊ตฌํ˜„์ฒด๊ฐ€ ์ถ”๊ฐ€์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ์˜ˆ์‹œ๋Š” JPA์˜ ๊ตฌํ˜„์ฒด์ธ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ์˜ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์ฝ๊ธฐ ์ „์šฉ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์กฐํšŒํ•˜์—ฌ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ์ฝ๊ธฐ ์ „์šฉ ์ฟผ๋ฆฌ ๋งŒ๋“ค๊ธฐ public interface MemberRepository extends JpaRepository { @QueryHints ( value=@QueryHint(name = "org.hibernate.readOnly", value = "true") ) Member findReadOnlyByUsername(String username); } Reference ์‹ค์ „! ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜ ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋Š” ๊ธฐ์กด..
@EntityGraph JPQL์˜ ํŽ˜์น˜ ์กฐ์ธ์„ ์กฐ๊ธˆ ๋” ํŽธํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ DATA JPA์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. @EntityGraph(attributePaths = {"ํŽ˜์น˜์กฐ์ธํ•  ์—”ํ‹ฐํ‹ฐ ํ•„๋“œ๋ช… 1", "ํ•„๋“œ๋ช… 2", ...}) ์˜ˆ์‹œ @Entity @Getter @Table(name = "member") class Member { @Id @Column(name = "member_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "team_id") private Team team;..
๋ฒŒํฌ ์—ฐ์‚ฐ ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๋ฒˆ์— ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋Š” ์—ฐ์‚ฐ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ˆœ์ˆ˜ JPA๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ executeUpdate()๋ฅผ ํ†ตํ•ด ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ๋“  ํšŒ์›์˜ ๋‚˜์ด๋ฅผ 1์”ฉ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ˆœ์ˆ˜ JPA๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. int resultCount = em.createQuery("update Member m set m.age = m.age").executeUpdate() Spring Data JPA์—์„œ์˜ ๋ฒŒํฌ ์—ฐ์‚ฐ @Modifying์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. public interface MemberRepository extends JpaRepository { @Modifying @Query("update Member m set m.age = m.a..
๋ง ๋ž‘
'๐Ÿ๏ธ Spring/JPA' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๊ธ€ ๋ชฉ๋ก (2 Page)