Repository와 Service 계층을 분리하여 사용하는 이유를 학습하였다. 이전 JDBC 프로젝트에서는 Main 클래스가 Repository를 직접 호출하여 데이터를 처리했지만, 이번 프로젝트에서는 Controller → Service → Repository 구조를 적용하여 계층별 역할을 명확하게 분리하였다.
또한 JdbcTemplate과 RowMapper를 이용하여 기존 JDBC 코드보다 훨씬 간결하게 데이터베이스를 다루는 방법을 익혔으며, @Transactional을 통해 여러 작업을 하나의 트랜잭션으로 관리하는 방법도 함께 학습하였다.
그리고 Spring은 단순히 JDBC를 대신해 주는 프레임워크가 아니라 객체 간의 역할을 명확하게 나누고 유지보수성을 높여주는 구조를 제공하는 프레임워크라는 점을 이해하게 되었다.
| 학습 내용 | 상세 내용 |
|---|---|
| Repository Interface | 데이터 접근 기능을 정의하는 인터페이스이다. |
| CRUD | Create, Read, Update, Delete 기능을 하나의 인터페이스에서 관리한다. |
| 인터페이스 | 구현체가 바뀌어도 사용하는 코드는 변경하지 않아도 된다. |
| 추상화 | 구현 방법보다 기능 자체를 먼저 정의하는 객체지향 설계 방식이다. |
public interface BankAccountRepository {
void save(Account account);
void update(Account account);
List<Account> findAll();
Account findById(long id);
void deleteById(long id);
}
이번 프로젝트에서는 Repository를 인터페이스로 먼저 작성하였다.
인터페이스에는
기능만 정의하였다.
실제 SQL은 작성하지 않는다.
즉,
무엇을 할 것인가
만 정의한다.
실제로
어떻게 할 것인가
는 구현 클래스가 담당한다.
예를 들어
현재는
SQLAccountRepository
를 사용하지만
나중에는
MongoRepository
또는
RedisRepository
로 변경할 수도 있다.
Controller와 Service는
Repository가 어떻게 구현되어 있는지 알 필요가 없다.
오직
save()
findAll()
findById()
만 알고 있으면 된다.
Controller
↓
Service
↓
AccountRepository
↓
SQLAccountRepository
이러한 구조를
다형성(Polymorphism)
이라고 한다.
| 느낀 점 | 내용 |
|---|---|
| 인터페이스 | 구현보다 기능을 먼저 설계하는 객체지향 방식을 이해하였다. |
| 유지보수 | 구현체가 변경되어도 다른 코드를 수정하지 않아도 되는 장점을 알게 되었다. |
| 다형성 | 인터페이스를 사용하는 이유를 실제 프로젝트를 통해 이해하였다. |
| 학습 내용 | 상세 내용 |
|---|---|
| JdbcTemplate | Spring에서 제공하는 JDBC 도우미 클래스이다. |
| RowMapper | 조회 결과(ResultSet)를 객체로 변환하는 인터페이스이다. |
| query() | 여러 데이터를 조회한다. |
| queryForObject() | 하나의 데이터를 조회한다. |
| update() | INSERT, UPDATE, DELETE를 수행한다. |
@Repository
@RequiredArgsConstructor
public class SqlAccountRepository
implements AccountRepository {
private final JdbcTemplate jdbcTemplate;
}
기존 JDBC에서는
Connection
PreparedStatement
ResultSet
을 모두 직접 생성해야 했다.
하지만 Spring에서는
JdbcTemplate
하나만 있으면
이 모든 과정을 내부에서 자동으로 처리해 준다.
즉,
개발자는
SQL만 작성하면 된다.
JdbcTemplate
↓
Connection 생성
↓
PreparedStatement 생성
↓
SQL 실행
↓
ResultSet 반환
↓
Connection 종료
이 과정을 Spring이 모두 대신 수행한다.
jdbcTemplate.update(query, account.getName());
update() 메서드는
INSERT
UPDATE
DELETE
모두 수행할 수 있다.
반환값은
영향 받은 행(Row)의 개수이다.
여러 개 조회
jdbcTemplate.query()
한 개 조회
jdbcTemplate.queryForObject()
를 사용하였다.
Repository에는
private static final RowMapper<Account>
가 존재한다.
RowMapper는
ResultSet을
객체로 변환하는 역할을 수행한다.
즉,
ResultSet
↓
Account 객체
변환기 역할을 한다.
SELECT
↓
ResultSet
↓
RowMapper
↓
Account
↓
List<Account>
| 기존 JDBC | JdbcTemplate |
|---|---|
| Connection 직접 생성 | 자동 생성 |
| Statement 생성 | 자동 생성 |
| close() 호출 | 자동 처리 |
| SQLException 처리 | Spring이 관리 |
| 느낀 점 | 내용 |
|---|---|
| 코드 간결화 | 반복되던 JDBC 코드가 크게 줄어들었다. |
| RowMapper | ResultSet을 객체로 변환하는 과정이 매우 편리하였다. |
| Spring의 역할 | Spring이 반복적인 작업을 자동으로 처리해 준다는 점을 체감하였다. |
| 학습 내용 | 상세 내용 |
|---|---|
| Service Layer | 비즈니스 로직을 담당하는 계층이다. |
| @Service | Service Bean으로 등록한다. |
| @Transactional | 여러 작업을 하나의 트랜잭션으로 관리한다. |
| DTO → Entity | 사용자의 입력을 Entity로 변환한다. |
| Entity → DTO | 조회 결과를 ViewDTO로 변환한다. |
@Service
@RequiredArgsConstructor
public class BankServiceImpl implements BankService{
private final AccountRepository repository;
}
Service는
Controller와 Repository 사이에서
중간 역할을 수행한다.
즉,
Controller는
Repository를 모른다.
Repository 역시
Controller를 모른다.
둘 사이를
Service가 연결한다.
Controller
↓
BankService
↓
Repository
Account account =
Account.builder()
.name(dto.name())
.build();
FormDTO를
Entity로 변환하였다.
그 이후
repository.save(account);
를 호출한다.
Repository는
Entity를 반환한다.
하지만
Controller는
ViewDTO를 원한다.
그래서
AccountViewDTO.fromEntity(...)
를 호출하여
DTO로 변환하였다.
수정 과정은
조금 더 복잡하다.
DTO
↓
Repository.findById()
↓
Entity
↓
이름 변경
↓
Repository.update()
즉,
기존 Entity를 조회한 뒤
필드만 변경하여
Repository에게 전달한다.
@Transactional
은
여러 작업을
하나의 작업처럼 처리한다.
예를 들어
계좌 생성
↓
로그 저장
↓
알림 발송
세 작업 중
하나라도 실패하면
모두 취소된다.
이를
Rollback이라고 한다.
BEGIN
↓
SQL1
↓
SQL2
↓
SQL3
↓
COMMIT
(실패 시 ROLLBACK)
| Controller | Service |
|---|---|
| 요청 처리 | 비즈니스 로직 |
| 화면 연결 | 업무 처리 |
| View 반환 | Repository 호출 |
Service를 분리하면
Controller가 훨씬 단순해지고
비즈니스 로직을 한곳에서 관리할 수 있다.
| 느낀 점 | 내용 |
|---|---|
| Service Layer | 단순히 Repository를 호출하는 것이 아니라 비즈니스 규칙을 관리하는 계층이라는 점을 이해하였다. |
| Transaction | 여러 작업을 하나의 작업 단위로 묶는 이유를 배웠다. |
| Spring 구조 | Controller, Service, Repository를 분리하면 유지보수성과 확장성이 크게 향상된다는 점을 느꼈다. |