SQL 만 책임지는 계층
@Service
public class BoardService {
public Board find(int num) {
// SQL 직접 작성, JDBC 직접 사용
Connection c = dataSource.getConnection();
PreparedStatement ps = c.prepareStatement(
"SELECT num, title, writer, content FROM myboard WHERE num=?");
// ... 30 줄
}
}
Service 가 비즈니스 로직 + DB 접근을 모두 책임 → 단위 테스트 불가능, 변경 영향 큼.
식당의 「식재료 창고 관리자」. 셰프(Service)는 「김치 한 통 가져와」 라고만 부탁. 어떻게 가져오는지(SQL)는 창고 관리자의 일.
package com.smhrd.mapper;
@Mapper
public interface BoardMapper {
Board selectOne(int num);
List<Board> selectList();
void insert(Board b);
void update(Board b);
void delete(int num);
}
👉 메서드 시그니처만 — 비즈니스 로직 없음.
| 이름 | 출처 | 본 과정에서 |
|---|---|---|
| DAO | 전통적 패턴 (Data Access Object) | 같은 의미로 사용 가능 |
| Repository | DDD 의 개념. Spring 권장 | @Repository 어노테이션 |
| @Mapper | MyBatis 의 어노테이션 | 본 과정 사용 — Mapper 인터페이스 자동 등록 |
👉 본 과정은 「Mapper」 라는 단어를 우선 사용. DAO·Repository 는 동의어.
@Repository
public class JdbcBoardDao {
@Autowired private JdbcTemplate jdbc;
public Board selectOne(int num) {
return jdbc.queryForObject(
"SELECT num, title, writer, content FROM myboard WHERE num = ?",
new BeanPropertyRowMapper<>(Board.class), num
);
}
}
@Repository 의 효과:
package com.smhrd.mapper;
@Mapper // ⭐ MyBatis 가 자동 등록
public interface BoardMapper {
List<Board> selectList();
}
<!-- com/smhrd/mapper/BoardMapper.xml -->
<mapper namespace="com.smhrd.mapper.BoardMapper">
<select id="selectList" resultType="com.smhrd.domain.Board">
SELECT num, title, writer, content
FROM myboard ORDER BY num DESC
</select>
</mapper>
👉 본 과정은 인터페이스 + XML 조합. 구현 클래스 직접 안 만듦. MyBatis 가 자동 구현.
👉 「SQL 한 번에 하는 일」 까지가 DAO 의 책임.
@Service
public class BoardService {
@Autowired
private BoardMapper mapper; // ⭐ 의존 방향: Service → Mapper
public Board find(int num) {
return mapper.selectOne(num);
}
}
@Service
public class OrderService {
@Autowired private OrderMapper orderMapper;
@Autowired private ItemMapper itemMapper;
@Autowired private PaymentMapper paymentMapper;
@Transactional
public void order(...) {
Item i = itemMapper.findById(itemId); // ① 재고
orderMapper.insert(order); // ② 주문
itemMapper.decreaseStock(itemId, qty); // ③ 차감
paymentMapper.insert(payment); // ④ 결제 기록
}
}
👉 여러 Mapper 를 「조합」 하는 일이 Service 의 핵심. 한 비즈니스 트랜잭션 단위로 묶임.
| 실수 | 증상 |
|---|---|
| @Mapper 빠뜨림 | "No qualifying bean of type 'BoardMapper'" |
| Service 에 SQL 직접 작성 | 책임 분리 깨짐 |
| Mapper 에서 비즈니스 로직 | 같은 로직이 여러 Mapper 에 중복 |
| Mapper 가 다른 Mapper 호출 | 의존 관계 복잡. Service 거쳐야 함 |
Service 와 Mapper 가 따로 있다는 정도만 안다.
Mapper 의 단 하나의 책임 = SQL. 비즈니스 로직은 안 들어가는 이유를 안다.