Service 작성 가이드
기본 원칙
- Interface 작성 안 함 — Service 클래스 직접 사용
@Service,@RequiredArgsConstructor,@Slf4j필수- 쓰기 트랜잭션:
@Transactional(rollbackFor = Exception.class) - 읽기 트랜잭션:
@Transactional(readOnly = true) - HTTP 관련 객체 (
HttpServletRequest,HttpSession) 직접 사용 금지 - 하나의 메서드는 하나의 역할만 수행
서비스 클래스 기본 구조
@Service
@RequiredArgsConstructor
@Slf4j
public class UserService {
private final UserMapper userMapper;
/**
* 사용자 단건 조회
*/
@Transactional(readOnly = true)
public UserVo get(UserVo vo) {
return userMapper.get(vo);
}
/**
* 사용자 목록 조회
*/
@Transactional(readOnly = true)
public List<UserVo> getList(UserVo vo) {
return userMapper.getList(vo);
}
/**
* 사용자 전체 수 조회
*/
@Transactional(readOnly = true)
public int getTotalCount(UserVo vo) {
return userMapper.getTotalCount(vo);
}
/**
* 사용자 등록
*/
@Transactional(rollbackFor = Exception.class)
public void regist(UserVo vo) {
userMapper.regist(vo);
}
/**
* 사용자 수정
*/
@Transactional(rollbackFor = Exception.class)
public void update(UserVo vo) {
userMapper.update(vo);
}
/**
* 사용자 삭제
*/
@Transactional(rollbackFor = Exception.class)
public void delete(UserVo vo) {
userMapper.delete(vo);
}
}
트랜잭션 규칙
| 메서드 성격 | 트랜잭션 어노테이션 |
|---|---|
| 조회 (SELECT) | @Transactional(readOnly = true) |
| 쓰기 (INSERT/UPDATE/DELETE) | @Transactional(rollbackFor = Exception.class) |
// 읽기 전용 트랜잭션
@Transactional(readOnly = true)
public UserVo get(UserVo vo) {
return userMapper.get(vo);
}
// 쓰기 트랜잭션 — 모든 예외에서 롤백
@Transactional(rollbackFor = Exception.class)
public void regist(UserVo vo) {
userMapper.regist(vo);
}
복합 트랜잭션 (여러 Mapper 호출)
@Transactional(rollbackFor = Exception.class)
public void registOrder(OrderVo vo) {
// 주문 등록
orderMapper.regist(vo);
// 주문 상세 등록 (같은 트랜잭션)
for (OrderDetailVo detail : vo.getDetailList()) {
detail.setOrderSn(vo.getOrderSn());
orderDetailMapper.regist(detail);
}
// 재고 차감
stockMapper.decrease(vo);
}
비즈니스 검증
Service에서 비즈니스 규칙을 검증한다.
@Transactional(rollbackFor = Exception.class)
public void regist(UserVo vo) {
// 비즈니스 규칙 검증
if (userMapper.existsByUserId(vo.getUserId()) > 0) {
throw new BusinessException("이미 사용 중인 아이디입니다.");
}
userMapper.regist(vo);
log.info("사용자 등록 완료: userId={}", vo.getUserId());
}
로깅
// 주요 비즈니스 이벤트 INFO 로그
log.info("사용자 등록: userId={}", vo.getUserId());
// 경고 상황 WARN 로그
log.warn("사용자 조회 결과 없음: userSn={}", vo.getUserSn());
// 예외 ERROR 로그
log.error("사용자 등록 실패: userId={}", vo.getUserId(), e);
체크리스트
- [ ] Interface 작성 안 함
- [ ]
@Service,@RequiredArgsConstructor,@Slf4j선언 - [ ] 읽기 메서드:
@Transactional(readOnly = true) - [ ] 쓰기 메서드:
@Transactional(rollbackFor = Exception.class) - [ ] HTTP 관련 객체 미사용
- [ ] 비즈니스 검증은 Service 레이어에서 처리