์คํ๋ง ๋ฐ์ดํฐ 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..
๐๏ธ Spring/JPA
์คํ๋ง ๋ถํธ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์๋ฌด๋ฐ ์ค์ ์์ด ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค. ์ฌ์ฉ ์ @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..