26/07/16 IL(I Learned) - Step 3

Repository 패턴과 CRUD 구현을 통한 데이터 관리

단순히 SQL을 실행하는 단계에서 더 나아가 객체를 데이터베이스에 저장하고 관리하는 Repository 패턴을 구현해 보았다. 이전까지는 SELECT 문을 실행하여 데이터를 조회하는 것에 집중했다면, 이번에는 Create, Read, Update, Delete(CRUD)를 하나의 Repository 클래스에 모아 관리하면서 객체지향적인 데이터 접근 방식을 경험하였다.

또한 record를 이용하여 데이터를 표현하고, DBUtil 클래스로 데이터베이스 연결을 공통화하면서 유지보수성과 재사용성을 높이는 방법도 함께 학습하였다.


1) 객체 생성 (Record)

학습 내용상세 내용
RecordJava에서 데이터를 저장하기 위한 불변(Immutable) 객체를 간단하게 생성할 수 있는 문법이다.
Immutable Object생성 이후 내부 데이터를 변경할 수 없는 객체이다.
DTO(Data Transfer Object)계층 간 데이터를 전달하기 위한 객체로 많이 사용된다.
자동 생성 기능Getter, equals(), hashCode(), toString() 등이 자동으로 생성된다.
코드 간결화기존 클래스보다 훨씬 적은 코드로 동일한 기능을 구현할 수 있다.
public record SideDish(
        long sideDishId,
        String sideDishName
) {
}

이번 실습에서는 Java의 Record를 이용하여 반찬 정보를 저장하는 객체를 생성하였다.

기존 클래스를 작성하려면 다음과 같은 코드가 필요하다.

  • 필드 선언
  • 생성자
  • Getter
  • equals()
  • hashCode()
  • toString()

하지만 Record는

public record SideDish(
        long sideDishId,
        String sideDishName
){}

한 줄만 작성하면 위 기능들이 자동으로 생성된다.

또한 Record는 생성 이후 값을 변경할 수 없기 때문에 데이터가 의도치 않게 수정되는 것을 방지할 수 있다.

특히 데이터베이스에서 조회한 데이터를 표현하는 객체는 대부분 값을 변경할 필요가 없기 때문에 Record가 매우 적합하다는 점을 알게 되었다.


기존 클래스와 Record 비교

기존 클래스Record
Getter 작성 필요자동 생성
생성자 작성자동 생성
equals 작성자동 생성
hashCode 작성자동 생성
toString 작성자동 생성
코드 김매우 짧음

왜 Record를 사용할까?

데이터를 저장하기 위한 객체는

  • 데이터를 계산하는 기능보다
  • 데이터를 전달하는 역할이 훨씬 많다.

따라서

"데이터만 표현하는 객체"

에는 Record가 가장 적합하다는 것을 배웠다.

느낀 점내용
코드 간결성Record 하나만으로 수십 줄의 코드를 줄일 수 있다는 점이 인상적이었다.
불변 객체데이터를 안전하게 관리하는 방법을 이해하였다.
DTO 활용앞으로 API 응답 객체를 만들 때 Record를 적극 활용할 수 있을 것 같다.

2) DBUtil

학습 내용상세 내용
Utility Class공통 기능을 제공하는 클래스이다.
static 메서드객체 생성 없이 사용할 수 있는 메서드이다.
환경 변수URL, USER, PASSWORD를 안전하게 관리한다.
DriverManagerConnection 객체를 생성한다.
코드 재사용여러 클래스에서 동일한 Connection 생성 코드를 공유한다.
public class DBConnectionUtil {

    private DBConnectionUtil(){}

    public static Connection openConnection()
            throws SQLException{

        Class.forName("org.postgresql.Driver");

        return DriverManager.getConnection(
                URL,
                USER,
                PASSWORD
        );

    }

}

DB 연결은 모든 Repository에서 공통적으로 수행된다.

만약 DB 연결 코드를

  • 회원 Repository
  • 게시판 Repository
  • 주문 Repository

마다 작성한다면

동일한 코드가 수십 번 반복된다.

그래서

DBUtil

클래스를 만들어

Connection 생성 기능을 하나로 모아두었다.

이후에는

Connection conn = DBUtil.getConnection();

한 줄만 작성하면 된다.

이러한 구조는

유지보수성과 재사용성을 크게 높여준다.


Utility Class의 장점

장점설명
코드 중복 제거Connection 생성 코드를 한 번만 작성
유지보수URL 변경 시 한 곳만 수정
보안환경 변수 사용
재사용모든 Repository에서 사용 가능

환경 변수를 사용하는 이유

실습에서는

System.getenv()

를 사용하였다.

그 이유는

DB 비밀번호를

String PASSWORD="1234";

처럼 코드에 작성하면

GitHub에 업로드될 위험이 있기 때문이다.

환경 변수는 운영체제에 저장되므로

소스 코드가 공개되어도 비밀번호는 노출되지 않는다.

실무에서는

  • Spring Boot
  • application.yml
  • DataSource
  • HikariCP

를 이용하여 Connection을 관리하지만

결국 내부적으로는

DriverManager를 이용한 Connection 생성 과정을 거친다.

이번 실습은 그 원리를 직접 구현해본 경험이었다.

느낀 점내용
코드 재사용공통 기능을 Utility 클래스로 만드는 이유를 이해하였다.
보안환경 변수 관리의 중요성을 알게 되었다.
Spring 이해Spring이 내부적으로 하는 일을 직접 구현해보니 프레임워크의 역할이 더욱 명확하게 느껴졌다.

3) BanchanRepository

학습 내용상세 내용
Repository Pattern데이터 접근을 담당하는 클래스를 별도로 분리하는 설계 방식이다.
CRUDCreate, Read, Update, Delete 기능을 하나의 Repository에서 관리한다.
PreparedStatement모든 SQL 실행에 사용하여 보안성을 높였다.
Transaction여러 작업을 하나의 작업 단위로 처리하였다.
ResultSet조회 결과를 Record 객체로 변환하였다.

Repository 패턴이란?

Repository는

데이터베이스와 직접 통신하는 역할만 담당하는 클래스

이다.

즉,

Controller가 SQL을 직접 작성하지 않는다.

Service도 SQL을 작성하지 않는다.

오직 Repository만 SQL을 작성한다.

Repository 구조

Controller

      │

      ▼

Service

      │

      ▼

Repository

      │

      ▼

Database

이 구조를 사용하면

각 클래스의 역할이 명확하게 분리된다.

CRUD 구현

이번 Repository에서는

메서드기능
save()데이터 저장(Create)
findById()단건 조회(Read)
findAll()전체 조회(Read)
update()수정(Update)
deleteById()삭제(Delete)

를 모두 구현하였다.


save() 구현 과정

객체 생성

↓

Connection 생성

↓

PreparedStatement 생성

↓

executeUpdate()

↓

COMMIT

데이터 저장은

SELECT가 아니라

INSERT 문을 실행하므로

executeUpdate()를 사용하였다.


update()

수정은

ID를 기준으로 수행하였다.

UPDATE banchan

SET name=?

WHERE id=?

ID가 동일한 데이터를 찾아

새로운 이름으로 변경하였다.

이 과정에서

Primary Key의 중요성을 이해할 수 있었다.


delete()

삭제 역시

ID를 이용하였다.

삭제 성공 여부는

executeUpdate()

가 반환하는

영향 받은 행(Row)의 개수로 확인하였다.

0이면

삭제 실패

1이면

삭제 성공이다.


Transaction을 사용하는 이유

이번 실습에서는

START TRANSACTION

SQL 실행

COMMIT

순서로 작성하였다.

트랜잭션은

여러 작업을 하나의 작업처럼 처리하기 위한 기능이다.

만약 중간에 오류가 발생하면

ROLLBACK을 수행하여

원래 상태로 되돌릴 수 있다.


CRUD 전체 흐름

사용자 요청

↓

Repository 호출

↓

Connection 생성

↓

PreparedStatement 생성

↓

SQL 실행

↓

ResultSet 또는 실행 결과 반환

↓

Connection 종료

이 흐름이

JDBC CRUD의 핵심이라는 것을 이해하였다.


느낀 점

느낀 점내용
객체지향 설계SQL을 Repository로 분리하는 이유를 이해하였다.
CRUD 구현데이터 저장부터 삭제까지 하나의 클래스로 관리하는 구조를 익혔다.
트랜잭션여러 작업을 하나로 묶는 이유를 이해하였다.
실무 연결Spring Data JPA의 JpaRepository가 이번에 구현한 Repository와 같은 역할이라는 점을 알게 되었다.
profile
예 마 함 가보입시더

0개의 댓글