1๏ธโƒฃ JPA (Java Persistence API)

๊ฐœ์š”

JPA๋Š” ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ORM (Object-Relational Mapping)์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์ค€ API๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ฐ์ฒด ๊ฐ„์˜ ๋งคํ•‘์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, SQL ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์™€ ํ•จ๊ป˜ Hibernate๋Š” JPA์˜ ๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ๊ตฌํ˜„์ฒด๋กœ, JPA์˜ ๊ธฐ๋Šฅ์„ ๋”์šฑ ๊ฐ•ํ™”ํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ๊ธฐ๋Šฅ ๋ฐ ๊ฐœ๋…

โœ”๏ธ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘(Entity Mapping)

JPA๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”์„ ์ž๋ฐ” ํด๋ž˜์Šค(์—”ํ‹ฐํ‹ฐ)์™€ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, @Entity ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ž˜์Šค๋ฅผ ์—”ํ‹ฐํ‹ฐ๋กœ ์„ ์–ธํ•˜๊ณ , @Id, @Column ๋“ฑ์˜ ์• ๋„ˆํ…Œ์ด์…˜์œผ๋กœ ๊ฐ ํ•„๋“œ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปฌ๋Ÿผ์— ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
}

โœ”๏ธ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ (Query Method)

JPA๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ์ฟผ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 * ๊ณต์‹๋ฌธ์„œ ์ฐธ์กฐ

public interface UserRepository extends JpaRepository<User, Long> {
// Spring Data JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜์—ฌ, ๋ฉ”์„œ๋“œ ์ด๋ฆ„์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑ
List<User> findByName(String name);
}

โœ”๏ธ์—ฐ๊ด€ ๊ด€๊ณ„ ๋งคํ•‘

JPA๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ„์˜ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ์• ๋„ˆํ…Œ์ด์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, @ManyToOne, @OneToMany, ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—”ํ‹ฐํ‹ฐ ๊ฐ„์˜ ๋‹ค๋Œ€์ผ, ์ผ๋Œ€๋‹ค, ๋‹ค๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ด€๊ณ„๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์™ธ๋ž˜ ํ‚ค์™€ ์ผ์น˜ํ•˜๋ฉฐ, ๊ฐ์ฒด ๊ฐ„์˜ ์ฐธ์กฐ ๊ด€๊ณ„๋กœ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค. JPA์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ JOIN ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ด€๋ จ๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•จ๊ป˜ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Entity
public class User {
@OneToMany(mappedBy = "user") // ์‚ฌ์šฉ์ž(User)์™€์˜ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•˜๋ฉฐ, 'user' ํ•„๋“œ๋กœ ๋งคํ•‘โœจ
private List<Post> posts; // ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก
}
@Entity
public class Post {
@ManyToOne // ๊ฒŒ์‹œ๋ฌผ(Post)์™€์˜ ๋‹ค๋Œ€์ผ ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•˜๋ฉฐ, ๊ฒŒ์‹œ๋ฌผ์ด ์†ํ•œ ์‚ฌ์šฉ์ž(User)๋ฅผ ์ฐธ์กฐโœจ
private User user; // ๊ฒŒ์‹œ๋ฌผ์ด ์†ํ•œ ์‚ฌ์šฉ์ž
}

โœ”๏ธํŒจ์น˜ ์ „๋žต(Fetch Strategy)

JPA์—์„œ๋Š” ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋กœ๋“œํ•  ๋•Œ Eager์™€ Lazy ๋‘ ๊ฐ€์ง€ ํŒจ์น˜ ์ „๋žต์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Eager ํŒจ์น˜๋Š” ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฆ‰์‹œ ๋กœ๋“œํ•˜๊ณ , Lazy ํŒจ์น˜๋Š” ์‹ค์ œ๋กœ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

@Entity
public class User {
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
// FetchType ๊ธฐ๋ณธ๊ฐ’: Lazy - ์‚ฌ์šฉ์ž๊ฐ€ ์กฐํšŒ๋  ๋•Œ ๊ด€๋ จ๋œ ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก์ด ํ•„์š”ํ•  ๋•Œ๋งŒ ๋กœ๋“œ๋จโœจ
private List<Post> posts;
}
@Entity
public class Post {
@ManyToOne(fetch = FetchType.EAGER)
// FetchType ๊ธฐ๋ณธ๊ฐ’: Eager - ๊ฒŒ์‹œ๋ฌผ์ด ์กฐํšŒ๋  ๋•Œ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ์ฆ‰์‹œ ๋กœ๋“œ๋จโœจ
private User user;
}

โœ”๏ธCustomRepository ๊ตฌํ˜„

JPA๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋ฉด ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ์™ธ์— ์ถ”๊ฐ€์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‚˜ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ CustomRepository๋ฅผ ํ†ตํ•ด ์ปค์Šคํ…€ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ธฐ๋ณธ CRUD ๊ธฐ๋Šฅ ์™ธ์— ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‚˜ ํŠน์ • ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๋Š” ๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ฐ ์ฒ˜๋ฆฌ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋™์  ์ฟผ๋ฆฌ ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

โœ”๏ธEntityManager

JPA์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ๊ด€๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ EntityManager์ž…๋‹ˆ๋‹ค. ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์—”ํ‹ฐํ‹ฐ์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , JPQL ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋ฉฐ, ํŠธ๋žœ์žญ์…˜์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

 

2๏ธโƒฃ JPQL (Java Persistence Query Language)

๊ฐœ์š”

JPQL์€ JPA์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด๋กœ, SQL๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ ํ…Œ์ด๋ธ” ๋Œ€์‹  ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์™€ ๊ทธ ์†์„ฑ์„ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

JPQL ์ฟผ๋ฆฌ ์ž‘์„ฑ ๋ฐฉ๋ฒ•

โœ”๏ธ์• ๋…ธํ…Œ์ด์…˜ ๋ฐฉ์‹

์ด ๋ฐฉ๋ฒ•์€ @Query ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ JPQL ์ฟผ๋ฆฌ๋ฅผ ๋ฉ”์„œ๋“œ ์œ„์— ์ •์˜ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. Spring Data JPA์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋ฉ”์„œ๋“œ์˜ ์„ ์–ธ๋ถ€์— ์ฟผ๋ฆฌ๋ฅผ ๋ช…์‹œํ•จ์œผ๋กœ์จ, ๋ณด๋‹ค ๊ฐ„๊ฒฐํ•˜๊ณ  ์ง๊ด€์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

public interface PostRepository extends CrudRepository<Post, Long> {
// @Query ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์„œ๋“œ์— ์ง์ ‘ JPQL ์ฟผ๋ฆฌ ์ •์˜โœจ
@Query("SELECT p FROM Post p WHERE p.user.id = :userId")
List<Post> findByUserId(@Param("userId") Long userId);
}

โœ”๏ธEntityManager ๋ฐฉ์‹

์ด ๋ฐฉ๋ฒ•์€ EntityManager๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JPQL ์ฟผ๋ฆฌ๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋ณด๋‹ค ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋‚˜ ๋™์  ์ฟผ๋ฆฌ ์ž‘์„ฑ์ด ํ•„์š”ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. JPQL ์ฟผ๋ฆฌ๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ •์˜ํ•˜๊ณ , createQuery() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

public class PostService {
// JPA์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ๊ด€๋ฆฌํ•˜๋Š” EntityManagerโœจ
@PersistenceContext
private EntityManager entityManager;
public void updatePostContent(Long postId, String newContent) {
// ๊ฒŒ์‹œ๋ฌผ ID์— ๋”ฐ๋ผ ๋‚ด์šฉ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” JPQL ์ฟผ๋ฆฌ
String sql = "UPDATE Post p SET p.content = :content WHERE p.id = :postId";
Query query = entityManager.createQuery(sql); // EntityManager๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JPQL ์ฟผ๋ฆฌ ์ƒ์„ฑโœจ
query.setParameter("content", newContent);
query.setParameter("postId", postId);
int result = query.executeUpdate(); // ์ฟผ๋ฆฌ ์‹คํ–‰
}
}

์ฃผ์š” ๊ธฐ๋Šฅ ๋ฐ ๊ฐœ๋…

โœ”๏ธFetch ์กฐ์ธ

Fetch ์กฐ์ธ์€ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•จ๊ป˜ ๋กœ๋“œํ•˜์—ฌ N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ค๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Fetch ์กฐ์ธ์„ ์‚ฌ์šฉํ•  ๋•Œ, ์ค‘๋ณต๋œ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ DISTINCT ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ค‘๋ณต๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ์—์„œ ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

public class PostRepositoryCustomImpl implements PostRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
public List<Post> fetchPostsWithUsers() {
// Fetch ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ Post์™€ User๋ฅผ ํ•จ๊ป˜ ๋กœ๋“œํ•˜๊ณ  ์ค‘๋ณต๋œ ๊ฒŒ์‹œ๋ฌผ ์ œ๊ฑฐโœจ
String jpql = "SELECT DISTINCT p FROM Post p JOIN FETCH p.user";
List<Post> posts = entityManager.createQuery(jpql, Post.class)
.getResultList();
return posts; // ์—ฐ๊ด€๋œ User ๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ ๋กœ๋“œ๋œ Post ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
}
}

โœ”๏ธ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ

JPQL ๋Œ€์‹  SQL์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ๋Š” ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ SQL ๋ฌธ๋ฒ•์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์œผ๋กœ, ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠน์ • ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

public interface PostRepository extends CrudRepository<Post, Long> {
// @Query ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์„œ๋“œ์— ์ง์ ‘ ๋„ค์ดํ‹ฐ๋ธŒ SQL ์ฟผ๋ฆฌ ์ •์˜โœจ
@Query(value = "SELECT * FROM post WHERE user_id = :userId", nativeQuery = true)
List<Post> findByUserId(@Param("userId") Long userId);
}

 

 

3๏ธโƒฃ QueryDSL (Query Domain-Specific Language)

์ฃผ์š” ๊ธฐ๋Šฅ ๋ฐ ๊ฐœ๋…

โœ”๏ธํƒ€์ž… ์•ˆ์ „์„ฑ

QueryDSL์€ ์ฟผ๋ฆฌ ๋ฌธ๋ฒ•์„ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•˜๋ฏ€๋กœ, ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ฟผ๋ฆฌ์˜ ์˜ค๋ฅ˜๋ฅผ ๋ฏธ๋ฆฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ์ค„์ด๊ณ , ์ฝ”๋“œ์˜ ์•ˆ์ •์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.

โœ”๏ธ๋™์  ์ฟผ๋ฆฌ ์ƒ์„ฑ

๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‚˜ ์‚ฌ์šฉ์ž ์š”๊ตฌ ์‚ฌํ•ญ์— ๋”ฐ๋ผ ์กฐ๊ฑด์„ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. BooleanBuilder ์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ฉด ๋™์  ์ฟผ๋ฆฌ๋ฅผ ์†์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

BooleanBuilder builder = new BooleanBuilder();
if (name != null) {
builder.and(user.name.eq(name)); // name ์กฐ๊ฑด ์ถ”๊ฐ€โœจ
}
if (otherCondition != null) {
builder.or(user.status.eq(otherCondition)); // ๋‹ค๋ฅธ ์กฐ๊ฑด์— OR ์‚ฌ์šฉโœจ
}
// ์ตœ์ข… ์ฟผ๋ฆฌ ์‹คํ–‰
List<User> users = queryFactory.selectFrom(user)
.where(builder) // ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ์กฐ๊ฑด์„ ์‚ฌ์šฉโœจ
.fetch();

โœ”๏ธ์กฐ์ธ (JOIN)

QueryDSL์—์„œ๋Š” ์กฐ์ธ ์—ฐ์‚ฐ์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์—ฐ๊ด€ ์ง€์–ด ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์—์„œ ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

QPost post = QPost.post;
QUser user = QUser.user;
// INNER JOIN ์˜ˆ์‹œ: ์ž‘์„ฑ์ž๊ฐ€ John์ธ ํฌ์ŠคํŠธ ์กฐํšŒ
List<Post> innerJoinPosts = queryFactory
.selectFrom(post)
.join(post.user, user) // INNER JOINโœจ
.where(user.name.eq("John"))
.fetch();
// LEFT JOIN ์˜ˆ์‹œ: ๋ชจ๋“  ํฌ์ŠคํŠธ์™€ ๊ทธ ์ž‘์„ฑ์ž๋ฅผ ์กฐํšŒํ•˜๋˜, ์ž‘์„ฑ์ž๊ฐ€ ์—†๋Š” ํฌ์ŠคํŠธ๋„ ํฌํ•จ
List<Post> leftJoinPosts = queryFactory
.selectFrom(post)
.leftJoin(post.user, user) // LEFT JOINโœจ
.fetch();
// ON ์ ˆ์„ ๋ช…์‹œํ•˜๋Š” LEFT JOIN ์˜ˆ์‹œ
List<Post> leftJoinWithOn = queryFactory
.selectFrom(post)
.leftJoin(post.user, user).on(user.age.gt(18)) // 18์„ธ ์ด์ƒ์ธ ์‚ฌ์šฉ์ž๋งŒโœจ
.fetch();

 

๐Ÿ’ก ์š”์•ฝ

JPA, JPQL, QueryDSL์€ ๊ฐ๊ฐ์˜ ๊ฐ•์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ์œ ๊ธฐ์ ์œผ๋กœ ํ™œ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์˜ ํšจ์œจ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. JPA๋Š” ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ๋งคํ•‘์„ ๋‹ด๋‹นํ•˜๊ณ , JPQL์€ ๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ์ฟผ๋ฆฌ ์ž‘์„ฑ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. QueryDSL์€ ๋™์  ์ฟผ๋ฆฌ ์ž‘์„ฑ๊ณผ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•˜์—ฌ ๋”์šฑ ๊ฐ•๋ ฅํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฒ˜๋ฆฌ ๋Šฅ๋ ฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ์„ธ ๊ฐ€์ง€ ๋„๊ตฌ๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋Œ€๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํšจ์œจ์ ์œผ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์œ ์ง€๋ณด์ˆ˜์™€ ํ™•์žฅ์„ฑ ์ธก๋ฉด์—์„œ๋„ ์œ ๋ฆฌํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ–์ถœ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

yewon31