▶ LEVEL 3
▷ 11. Transaction 심화
● 문제의 요구사항
1. 매니저 등록 요청을 기록하는 로그 테이블을 제작
- DB테이블명: log
2. 매니저 등록과는 별개로 로그 테이블에는 항상 요청 로그가 남아야한다.
- 매니저 등록은 실패할 수 있지만, 로그는 반드시 저장되어야한다.
- 로그 생성 기간은 반드시 필요하다.
- 그 외 로그에 들어가는 내용은 원하는 정보를 자유롭게 넣어야한다.
먼저 로그 기록을 받기 위한 로그 엔티티를 제작하도록 하자
@Entity
@Getter
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
@Table(name = "log")
public class Log extends Timestamped {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long managerId;
private String actions;
private String status;
private String message;
public Log(Long managerId, String actions, String status, String message) {
this.managerId = managerId;
this.actions = actions;
this.status = status;
this.message = message;
}
}
log엔티티에서는 "log"인 이름인 테이블을 생성하며 해당 엔티티에서는 managerId, actions, status, message값을 가진다.
그리고 로그 저장을 위해 리포지토리를 제작한다.
public interface LogRepository extends JpaRepository<Log, Long> {
}
그리고 매니저 등록과 로그 저장을 독립적인 트랙잭션으로 처리한 서비스 로직을 제작한다.
@Service
@RequiredArgsConstructor
public class LogService {
private final LogRepository logRepository;
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void saveLog(Long managerId, String actions, String status, String message){
Log log = new Log(managerId, actions, status, message);
logRepository.save(log);
}
}
여기서 @Transactional(propagation = Propagation.REQUIRES_NEW)를 사용하여 별도의 트랙잭션으로 저장되도록 설정했다.
이제 로그 서비스를 이용하여 manager가 생성되거나 삭제될 때 로그를 출력할 수 있도록 매니저 서비스에 구현한다.
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ManagerService {
private final ManagerRepository managerRepository;
private final UserRepository userRepository;
private final TodoRepository todoRepository;
private final LogService logService;
@Transactional
public ManagerSaveResponse saveManager(AuthUser authUser, long todoId, ManagerSaveRequest managerSaveRequest) {
// 일정을 만든 유저
User user = User.fromAuthUser(authUser);
Todo todo = todoRepository.findById(todoId)
.orElseThrow(() -> new InvalidRequestException("Todo not found"));
if (todo.getUser() == null || !ObjectUtils.nullSafeEquals(user.getId(), todo.getUser().getId())) {
throw new InvalidRequestException("담당자를 등록하려고 하는 유저가 유효하지 않거나, 일정을 만든 유저가 아닙니다.");
}
User managerUser = userRepository.findById(managerSaveRequest.getManagerUserId())
.orElseThrow(() -> new InvalidRequestException("등록하려고 하는 담당자 유저가 존재하지 않습니다."));
if (ObjectUtils.nullSafeEquals(user.getId(), managerUser.getId())) {
throw new InvalidRequestException("일정 작성자는 본인을 담당자로 등록할 수 없습니다.");
}
Long managerId = null;
try{
Manager newManagerUser = new Manager(managerUser, todo);
Manager savedManagerUser = managerRepository.save(newManagerUser);
managerId = savedManagerUser.getId();
logService.saveLog(managerId, "MANAGER_REGISTER", "SUCCESS", "매니저 등록 성공");
return new ManagerSaveResponse(
savedManagerUser.getId(),
new UserResponse(managerUser.getId(), managerUser.getEmail())
);
}catch (Exception e){
logService.saveLog(managerId, "MANAGER_REGISTER", "FAILURE", e.getMessage());
throw e;
}
}
public List<ManagerResponse> getManagers(long todoId) {
Todo todo = todoRepository.findById(todoId)
.orElseThrow(() -> new InvalidRequestException("Todo not found"));
List<Manager> managerList = managerRepository.findByTodoIdWithUser(todo.getId());
List<ManagerResponse> dtoList = new ArrayList<>();
for (Manager manager : managerList) {
User user = manager.getUser();
dtoList.add(new ManagerResponse(
manager.getId(),
new UserResponse(user.getId(), user.getEmail())
));
}
return dtoList;
}
@Transactional
public void deleteManager(AuthUser authUser, long todoId, long managerId) {
User user = User.fromAuthUser(authUser);
Todo todo = todoRepository.findById(todoId)
.orElseThrow(() -> new InvalidRequestException("Todo not found"));
if (todo.getUser() == null || !ObjectUtils.nullSafeEquals(user.getId(), todo.getUser().getId())) {
throw new InvalidRequestException("해당 일정을 만든 유저가 유효하지 않습니다.");
}
Manager manager = managerRepository.findById(managerId)
.orElseThrow(() -> new InvalidRequestException("Manager not found"));
if (!ObjectUtils.nullSafeEquals(todo.getId(), manager.getTodo().getId())) {
throw new InvalidRequestException("해당 일정에 등록된 담당자가 아닙니다.");
}
try{
managerRepository.delete(manager);
logService.saveLog(managerId, "MANAGER_DELETE", "SUCCESS", "매니저 삭제 성공");
}catch (Exception e){
logService.saveLog(managerId, "MANAGER_DELETE", "FAILURE", e.getMessage());
throw e;
}
}
}
이렇게 제작했는데 여기서 로그 서비스는 매니저를 등록하거나 삭제할 때 로그를 출력하며 실패했을 때에도 오류 메세지와 함께 출력되게 된다.
'TIL' 카테고리의 다른 글
| 플러스 주차 개인 과제 트러블 슈팅 TIL (0) | 2025.03.21 |
|---|---|
| 플러스 주차 개인 과제 TIL 6. (0) | 2025.03.17 |
| 플러스 주차 개인 과제 TIL 5. (0) | 2025.03.14 |
| 플러스 주차 개인과제 TIL 4. (0) | 2025.03.13 |
| 플러스 주차 개인과제 TIL 3. (0) | 2025.03.12 |