26/07/22 IL(I Learned) - MyBatis 2 (1)

Let's take a break·2026년 7월 27일

MyBatis 심화 기능 구현 (검색, 정렬, 다중 삭제)

이번 프로젝트에서는 단순 CRUD를 넘어 검색(Search), 정렬(Sort), 다중 삭제(Delete Multiple) 기능을 구현하면서 MyBatis의 동적 SQL 활용 방법을 학습하였다.

또한 DTO를 기능별로 세분화하여 사용자 입력을 더욱 명확하게 관리하는 구조를 경험하였다.


1) 검색 기능 구현

이전 프로젝트에서는 게시글 전체를 조회하거나 ID로 하나의 게시글을 조회하는 기능만 존재하였다.

findAll()

↓

findById()

하지만 이번 프로젝트에서는 사용자가 원하는 조건만 조회할 수 있도록 검색 기능이 추가되었다.


UserSearchDTO

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserSearchDTO {
    private String name;
    private String city;
    private Integer minAge;
}

검색 기능에서 가장 먼저 달라진 점은 검색 조건을 하나의 객체(DTO)로 관리한다는 것이다.

기존 프로젝트에서는 조회에 필요한 값이 거의 없었기 때문에 DTO가 필요하지 않았다.

하지만 검색은

  • 이름만 입력할 수도 있고
  • 도시만 입력할 수도 있고
  • 최소 나이만 입력할 수도 있다.

즉, 모든 값이 항상 존재하는 것이 아니기 때문에 Integer를 사용하여 null을 허용하도록 설계하였다.

이러한 방식은 검색 조건이 많아질수록 Controller의 매개변수를 줄이고 유지보수를 쉽게 만들어 준다.


Controller

@GetMapping("/search")
public String search(
        @ModelAttribute UserSearchDTO dto,
        Model model) {

    model.addAttribute(
            "users",
            userAccountService.search(dto)
    );

    return "user";
}

이전 프로젝트에서는

@GetMapping

하나로 모든 조회를 수행하였다.

이번 프로젝트에서는 검색 요청을 별도의 URL(/search)로 분리하였다.

사용자가 입력한 검색 조건은

Controller

↓

UserSearchDTO

↓

Service

↓

Mapper

순서로 전달된다.

Controller는 검색 조건을 직접 처리하지 않고 Service에게 전달하는 역할만 수행한다.


Service

public List<UserAccount> search(UserSearchDTO dto) {
    return userAccountMapper.search(dto);
}

Service 역시 복잡한 검색 로직을 작성하지 않는다.

검색 조건을 Mapper에게 전달하면 MyBatis가 XML의 동적 SQL을 실행하여 결과를 반환한다.

이처럼 검색 조건이 많아질수록 Service는 단순히 비즈니스 로직을 연결하는 역할만 담당한다.


2) 정렬 기능 구현

기존 프로젝트에서는 조회 결과가 항상 동일한 순서로 출력되었다.

이번 프로젝트에서는 사용자가 원하는 기준으로 정렬할 수 있도록 기능이 추가되었다.


Controller

@GetMapping("/sorted")
public String sorted(
        @RequestParam String sort,
        Model model) {

    model.addAttribute(
            "users",
            userAccountService.findAllSorted(sort)
    );

    return "user";
}

@RequestParam을 이용하여 사용자가 선택한 정렬 기준을 전달받는다.

예를 들어

/users/sorted?sort=name

이면 이름순으로,

/users/sorted?sort=age

이면 나이순으로 조회한다.

정렬 기준은 Service와 Mapper를 거쳐 SQL의 ORDER BY 절에 적용된다.


Service

public List<UserAccount> findAllSorted(String sort) {
    return userAccountMapper.findAllSorted(sort);
}

Service에서는 정렬 기준을 그대로 Mapper에 전달한다.

즉,

Controller

↓

sort

↓

Service

↓

Mapper

↓

ORDER BY

흐름으로 동작한다.


3) 다중 삭제 기능

이번 프로젝트에서 새롭게 구현한 기능 중 하나는 여러 사용자를 한 번에 삭제하는 기능이다.


Controller

@PostMapping("/delete")
public String delete(
        @RequestParam List<Long> ids) {

    userAccountService.deleteByIds(ids);

    return "redirect:/users";
}

이전 프로젝트에서는

delete(Long id)

처럼 하나의 PK만 전달하였다.

이번에는

List<Long> ids

를 사용하여 여러 개의 PK를 한 번에 전달한다.

체크박스를 이용하여 여러 사용자를 선택한 후 한 번의 요청으로 삭제할 수 있다.


Service

public void deleteByIds(List<Long> ids) {
    userAccountMapper.deleteByIds(ids);
}

코드 설명

Service는 전달받은 리스트를 Mapper에게 넘겨준다.

Mapper에서는 MyBatis의 <foreach> 기능을 사용하여

WHERE id IN (...)

형태의 SQL을 생성한다.

이전 프로젝트보다 SQL을 더욱 동적으로 작성할 수 있다는 점을 배울 수 있었다.


새롭게 배운 점

이전 프로젝트mybatis2 프로젝트
단순 CRUD검색 기능 추가
고정 조회정렬 기능 추가
단일 삭제다중 삭제
단순 DTOSearchDTO 추가
고정 SQL동적 SQL 활용

느낀 점

이번 프로젝트에서는 단순히 데이터를 저장하고 조회하는 수준을 넘어 사용자의 요구에 따라 데이터를 검색하고 정렬하며 여러 데이터를 한 번에 처리하는 기능을 구현하였다. 특히 UserSearchDTO를 이용하여 검색 조건을 하나의 객체로 관리하는 방식과, List<Long>을 활용한 다중 삭제 기능은 실제 웹 서비스에서 자주 사용되는 구현 방식이라는 점을 이해할 수 있었다.

0개의 댓글