Home > Backend Development > πŸ“š[Backend Development] Java Spring ν”„λ ˆμž„μ›Œν¬μ˜ 계측 - Data Access Layer (데이터 μ ‘κ·Ό 계측)

πŸ“š[Backend Development] Java Spring ν”„λ ˆμž„μ›Œν¬μ˜ 계측 - Data Access Layer (데이터 μ ‘κ·Ό 계측)
Backend Ddevelopment Component Layer Architecture

πŸ“š[Backend Development] Java Spring ν”„λ ˆμž„μ›Œν¬μ˜ 계측 - Data Access Layer (데이터 μ ‘κ·Ό 계측)

βœ… Data Access Layer (데이터 μ ‘κ·Ό 계측)

Data Access LayerλŠ” λΉ„μ¦ˆλ‹ˆμŠ€ 둜직과 λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό λΆ„λ¦¬ν•˜μ—¬ μ‹œμŠ€ν…œμ„ μœ μ—°ν•˜κ³  ν™•μž₯ κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€κΈ° μœ„ν•΄ μ‚¬μš©ν•©λ‹ˆλ‹€.

  • μ£Όμš” μ»΄ν¬λ„ŒνŠΈ : @Repository
  • μ—­ν•  : λ°μ΄ν„°λ² μ΄μŠ€(DB)에 직접 μ ‘κ·Όν•˜μ—¬ 데이터λ₯Ό CRUD(Create, Read, Update, Delete)ν•˜λŠ” 역할을 λ‹΄λ‹Ήν•©λ‹ˆλ‹€.
  • μ„€λͺ… : λΉ„μ¦ˆλ‹ˆμŠ€ 둜직과 λ°μ΄ν„°λ² μ΄μŠ€ μ‚¬μ΄μ˜ 닀리 역할을 ν•©λ‹ˆλ‹€. JPA(Java Persistence API)와 같은 κΈ°μˆ μ„ μ‚¬μš©ν•˜μ—¬ SQL 쿼리λ₯Ό 직접 닀루고, λ°μ΄ν„°μ˜ μ˜μ†μ„±(Persistence)을 κ΄€λ¦¬ν•©λ‹ˆλ‹€.

βœ… 1. JPA (Java Persistence API)

JPAλŠ” μžλ°” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” 방식을 μ •μ˜ν•œ β€˜λͺ…세’ λ˜λŠ” β€˜κ·œμΉ™β€™ μž…λ‹ˆλ‹€.

  • κ°œλ… : κ°œλ°œμžκ°€ 직접 SQL 쿼리λ₯Ό μž‘μ„±ν•˜λŠ” λŒ€μ‹ , 일반 μžλ°” 객체(Object)λ₯Ό 닀루듯이 μ½”λ“œλ₯Ό 짜면 JPAκ°€ μ•Œμ•„μ„œ μ μ ˆν•œ SQL을 μƒμ„±ν•˜μ—¬ λ°μ΄ν„°λ² μ΄μŠ€μ™€ ν†΅μ‹ ν•©λ‹ˆλ‹€. 이처럼 객체와 κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μžλ™μœΌλ‘œ μ—°κ²°ν•΄μ£ΌλŠ” κΈ°μˆ μ„ ORM(Object-Relational Mapping) 이라고 ν•˜λ©°, JPAλŠ” 이 ORM 기술의 ν‘œμ€€ κ·œκ²©μž…λ‹ˆλ‹€.

  • μ—­ν•  : SQL μ€‘μ‹¬μ˜ κ°œλ°œμ—μ„œ 객체 μ€‘μ‹¬μ˜ 개발둜 μ „ν™˜ν•˜μ—¬, κ°œλ°œμžκ°€ λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— 더 집쀑할 수 있게 λ„μ™€μ€λ‹ˆλ‹€. κ°€μž₯ 유λͺ…ν•œ JPA κ΅¬ν˜„μ²΄λ‘œλŠ” ν•˜μ΄λ²„λ„€μ΄νŠΈ(Hibernate) κ°€ μžˆμŠ΅λ‹ˆλ‹€.

πŸ“ λΉ„μœ  : JPAλŠ” β€˜μžλ™ λ²ˆμ—­κΈ°β€™μ™€ κ°™μŠ΅λ‹ˆλ‹€. κ°œλ°œμžλŠ” β€˜μžλ°” κ°μ²΄β€™λΌλŠ” μ–Έμ–΄λ‘œ λ§ν•˜λ©΄, JPAκ°€ β€˜SQLβ€™μ΄λΌλŠ” μ–Έμ–΄λ‘œ λ²ˆμ—­ν•˜μ—¬ λ°μ΄ν„°λ² μ΄μŠ€μ™€ μ†Œν†΅ν•˜κ³  κ·Έ κ²°κ³Όλ₯Ό λ‹€μ‹œ β€˜μžλ°” κ°μ²΄β€™λ‘œ λ²ˆμ—­ν•΄μ„œ λŒλ €μ€λ‹ˆλ‹€.

βœ… 2. λ°μ΄ν„°μ˜ μ˜μ†μ„± (Persistence)

μ˜μ†μ„±μ€ 데이터가 ν”„λ‘œκ·Έλž¨μ΄ μ’…λ£Œλ˜μ–΄λ„ 사라지지 μ•Šκ³  영ꡬ적으둜 μ €μž₯μ†Œμ— λ‚¨μ•„μžˆλŠ” νŠΉμ„±μ„ μ˜λ―Έν•©λ‹ˆλ‹€.

  • 일반적 κ°œλ… : μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ 껐닀 μΌœλ„ 데이터가 κ·ΈλŒ€λ‘œ λ‚¨μ•„μžˆλŠ” μƒνƒœλ₯Ό λ§ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ˜μ†μ„±μ„ 보μž₯ν•˜κΈ° μœ„ν•΄ λ°μ΄ν„°λ² μ΄μŠ€, 파일 μ‹œμŠ€ν…œ 등을 μ‚¬μš©ν•©λ‹ˆλ‹€.
  • JPAμ—μ„œμ˜ κ°œλ… (μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ) : JPAμ—μ„œλŠ” 쑰금 더 ꡬ체적인 의미둜 μ‚¬μš©λ©λ‹ˆλ‹€. β€˜μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ(Persistence Context)’ λŠ” JPAκ°€ μ—”ν‹°ν‹°(Entity) 객체듀을 κ΄€λ¦¬ν•˜λŠ” κ°€μƒμ˜ 곡간(μΊμ‹œ)μž…λ‹ˆλ‹€.
    • λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ‘°νšŒν•˜κ±°λ‚˜ μ €μž₯ν•  μ—”ν‹°ν‹°λŠ” 이 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— λ“€μ–΄κ°‘λ‹ˆλ‹€.
    • 일단 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— λ“€μ–΄μ˜¨ κ°μ²΄λŠ” JPAκ°€ 계속 μΆ”μ ν•˜λ©° λ³€ν™”λ₯Ό κ°μ§€ν•©λ‹ˆλ‹€.
    • νŠΈλžœμž­μ…˜μ΄ λλ‚˜λŠ” μ‹œμ μ—, JPAλŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ•ˆμ—μ„œ λ³€κ²½λœ 객체듀을 κ°μ§€ν•˜μ—¬ μžλ™μœΌλ‘œ UPDATE 쿼리λ₯Ό λ‚ λ € λ°μ΄ν„°λ² μ΄μŠ€μ— κ·Έ 변경사항을 λ°˜μ˜ν•©λ‹ˆλ‹€. 이 과정을 톡해 λ°μ΄ν„°μ˜ μ˜μ†μ„±μ΄ μœ μ§€λ©λ‹ˆλ‹€.

βœ… 3. Data Access LayerλŠ” μ–Έμ œ μ‚¬μš©ν•˜λ‚˜μš”?

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 데이터λ₯Ό 영ꡬ μ €μž₯μ†Œ(주둜 λ°μ΄ν„°λ² μ΄μŠ€)에 μ €μž₯ν•˜κ±°λ‚˜ μ‘°νšŒν•˜λŠ” λͺ¨λ“  μž‘μ—…μ— μ‚¬μš©λ©λ‹ˆλ‹€.
λΉ„μ¦ˆλ‹ˆμŠ€ 계측(Service)이 데이터 처리λ₯Ό μš”μ²­ν•˜λ©΄, 이 계측이 μ‹€μ§ˆμ μΈ λ°μ΄ν„°λ² μ΄μŠ€ 톡신을 λ‹΄λ‹Ήν•©λ‹ˆλ‹€.

βœ… 4. Data Access LayerλŠ” μ–΄λ””μ„œ μ‚¬μš©ν•˜λ‚˜μš”?

μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ•„ν‚€ν…μ²˜μ˜ κ°€μž₯ μ•ˆμͺ½, λ°μ΄ν„°λ² μ΄μŠ€μ™€ κ°€μž₯ κ°€κΉŒμš΄ 곳에 μœ„μΉ˜ν•©λ‹ˆλ‹€.
λΉ„μ¦ˆλ‹ˆμŠ€ 계측(Service)의 μš”μ²­μ„ λ°›μ•„ λ°μ΄ν„°λ² μ΄μŠ€μ™€ 직접 μƒν˜Έμž‘μš©ν•˜λŠ” μ΅œμ „μ„  역할을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.

βœ… 5. Data Access LayerλŠ” μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λ‚˜μš”?

주둜 @Repository μ–΄λ…Έν…Œμ΄μ…˜μ„ 뢙인 μΈν„°νŽ˜μ΄μŠ€λ‚˜ 클래슀둜 κ΅¬ν˜„ν•©λ‹ˆλ‹€.
특히 Spring Data JPAλ₯Ό μ‚¬μš©ν•˜λ©΄, JpaRepository와 같은 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μƒμ†λ°›λŠ” κ²ƒλ§ŒμœΌλ‘œλ„ 기본적인 CRUD κΈ°λŠ₯이 κ΅¬ν˜„λ˜μ–΄ 맀우 νŽΈλ¦¬ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // μ΄λ©”μΌλ‘œ μ‚¬μš©μžλ₯Ό μ°ΎλŠ” μ»€μŠ€ν…€ λ©”μ„œλ“œ
    Optional<User> findByEmail(String email);
}

βœ… 6. Data Access LayerλŠ” μ™œ μ‚¬μš©ν•˜λ‚˜μš”?

κ°€μž₯ μ€‘μš”ν•œ μ΄μœ λŠ” 데이터 μ ‘κ·Ό 기술의 μΊ‘μŠν™”μ™€ κ΄€μ‹¬μ‚¬μ˜ λΆ„λ¦¬μž…λ‹ˆλ‹€.

  • μœ μ—°μ„  및 ν™•μž₯μ„± : λ‚˜μ€‘μ— λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό MySQLμ—μ„œ Oracleμ΄λ‚˜ λ‹€λ₯Έ μ’…λ₯˜λ‘œ λ³€κ²½ν•˜λ”λΌλ„, λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ½”λ“œλŠ” μ „ν˜€ μˆ˜μ •ν•  ν•„μš” 없이 이 Data Access Layer의 κ΅¬ν˜„λ§Œ λ°”κΎΈλ©΄ λ©λ‹ˆλ‹€.

  • μœ μ§€λ³΄μˆ˜ μš©μ΄μ„± : λ°μ΄ν„°λ² μ΄μŠ€μ™€ κ΄€λ ¨λœ λͺ¨λ“  μ½”λ“œκ°€ ν•œκ³³μ— λͺ¨μ—¬μžˆμ–΄, SQL 쿼리 μ΅œμ ν™”λ‚˜ ν…Œμ΄λΈ” ꡬ쑰 λ³€κ²½ μ‹œ μˆ˜μ •ν•  뢀뢄을 μ°ΎκΈ° 쉽고 관리가 μš©μ΄ν•©λ‹ˆλ‹€.

  • μ—­ν•  뢄리 : λΉ„μ¦ˆλ‹ˆμŠ€ 계측은 β€˜λ¬΄μ—‡μ„ ν• μ§€β€™μ—λ§Œ μ§‘μ€‘ν•˜κ³ , 데이터 μ ‘κ·Ό 계측은 β€˜μ–΄λ–»κ²Œ 데이터λ₯Ό κ°€μ Έμ˜¬μ§€β€™μ—λ§Œ μ§‘μ€‘ν•˜κ²Œ ν•˜μ—¬ μ½”λ“œμ˜ 가독성과 λͺ…확성을 λ†’μž…λ‹ˆλ‹€.

βœ… @Repository

@RepositoryλŠ” λ°μ΄ν„°λ² μ΄μŠ€μ— 직접 μ ‘κ·Όν•˜λŠ” 클래슀(DAO)에 μ‚¬μš©λ˜λ©°, μ˜ˆμ™Έλ₯Ό μŠ€ν”„λ§μ˜ μΌκ΄€λœ λ°©μ‹μœΌλ‘œ λ³€ν™˜ν•΄μ£ΌλŠ” 역할을 ν•©λ‹ˆλ‹€.

βœ… 1. @RepositoryλŠ” μ–Έμ œ μ‚¬μš©λ˜λ‚˜μš”?

λ°μ΄ν„°λ² μ΄μŠ€μ™€ 직접 ν†΅μ‹ ν•˜μ—¬ 데이터λ₯Ό CRUD(생성, 쑰회, μˆ˜μ •, μ‚­μ œ)ν•˜λŠ” 객체λ₯Ό λ§Œλ“€ λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.
주둜 λ°μ΄ν„°λ² μ΄μŠ€μ˜ ν…Œμ΄λΈ”μ— μ ‘κ·Όν•˜λŠ” DAO(Data Access Object) ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€μ— μ μš©λ©λ‹ˆλ‹€.

βœ… 2. @RepositoryλŠ” μ–΄λ””μ„œ μ‚¬μš©λ˜λ‚˜μš”?

μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ•„ν‚€ν…μ²˜μ˜ Data Access Layer(데이터 μ ‘κ·Ό 계측)μ—μ„œ μ‚¬μš©λ©λ‹ˆλ‹€.
이 계측은 λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ μ²˜λ¦¬ν•˜λŠ” Service 계측과 μ‹€μ œ λ°μ΄ν„°λ² μ΄μŠ€ μ‚¬μ΄μ—μ„œ 데이터λ₯Ό μ£Όκ³  λ°›λŠ” 역할을 λ‹΄λ‹Ήν•©λ‹ˆλ‹€.

βœ… 3. @RepositoryλŠ” μ–΄λ–»κ²Œ μ‚¬μš©λ˜λ‚˜μš”?

ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€ μ„ μ–ΈλΆ€ μœ„μ— @Repository μ–΄λ…Έν…Œμ΄μ…˜μ„ λΆ™μ—¬μ£ΌκΈ°λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€.
특히 Spring Data JPAλ₯Ό μ‚¬μš©ν•˜λ©΄, JpaRepository μΈν„°νŽ˜μ΄μŠ€λ₯Ό μƒμ†λ°›λŠ” κ²ƒλ§ŒμœΌλ‘œλ„ μžλ™μœΌλ‘œ Repository둜 λ“±λ‘λ˜μ–΄ 기본적인 CRUD λ©”μ„œλ“œλ₯Ό λ°”λ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

// 이 μΈν„°νŽ˜μ΄μŠ€κ°€ λ°μ΄ν„°λ² μ΄μŠ€μ— μ ‘κ·Όν•˜λŠ” Repositoryμž„μ„ μ„ μ–Έν•©λ‹ˆλ‹€.
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // JpaRepositoryλ₯Ό μƒμ†λ°›μœΌλ©΄ 기본적인 CRUD(save, findById, findAll, delete λ“±)
    // λ©”μ„œλ“œκ°€ μžλ™μœΌλ‘œ μ œκ³΅λ©λ‹ˆλ‹€.
    
    // λ©”μ„œλ“œ 이름을 κ·œμΉ™μ— 맞게 μž‘μ„±ν•˜λ©΄, Spring Data JPAκ°€ μ•Œμ•„μ„œ
    // 쿼리λ₯Ό μƒμ„±ν•΄μ€λ‹ˆλ‹€. (예: μ΄λ©”μΌλ‘œ μ‚¬μš©μž μ°ΎκΈ°)
    Optional<User> findByEmail(String email);
}

βœ… 4. @RepositoryλŠ” μ™œ μ‚¬μš©λ˜λ‚˜μš”?

@Repositoryλ₯Ό μ‚¬μš©ν•˜λŠ” 주된 μ΄μœ λŠ” 두 κ°€μ§€μž…λ‹ˆλ‹€.

  • μ—­ν•  λͺ…μ‹œ (μ½”λ“œ 가독성) : 이 ν΄λž˜μŠ€κ°€ β€˜λ°μ΄ν„° μ €μž₯μ†Œμ— μ ‘κ·Όν•˜λŠ” 객체’ μž„μ„ λͺ…ν™•ν•˜κ²Œ λ‚˜νƒ€λƒ…λ‹ˆλ‹€. 이λ₯Ό 톡해 κ°œλ°œμžλŠ” 클래슀의 역할을 μ‰½κ²Œ νŒŒμ•…ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ˜ˆμ™Έ λ³€ν™˜ (Exception Translation) : @Repository의 κ°€μž₯ μ€‘μš”ν•œ κΈ°λŠ₯μž…λ‹ˆλ‹€. λ°μ΄ν„°λ² μ΄μŠ€λ§ˆλ‹€ λ°œμƒν•˜λŠ” μ˜ˆμ™Έ(e.g, MySQL의 MySQLIntegrityConstraintViolationException)κ°€ λ‹€λ¦…λ‹ˆλ‹€. @Repositoryκ°€ λΆ™μ–΄ 있으면, μŠ€ν”„λ§μ΄ μ΄λŸ¬ν•œ νŠΉμ • κΈ°μˆ μ— 쒅속적인 μ˜ˆμ™Έλ“€μ„ μŠ€ν”„λ§μ˜ μΌκ΄€λœ μ˜ˆμ™Έ 계측인 DataAccessException으둜 λ³€ν™˜ν•΄μ€λ‹ˆλ‹€. 덕뢄에 κ°œλ°œμžλŠ” λ°μ΄ν„°λ² μ΄μŠ€ μ’…λ₯˜μ™€ 상관없이 μΌκ΄€λœ λ°©μ‹μœΌλ‘œ μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.