Contents
see List작성일 2014. 09. 29.
MyBatis Map이나 Bean 없이 2개 이상 파라미터 전달
MyBatis에서 Map이나 DTO Bean을 만들지 않고 여러 파라미터를 Mapper 메서드에 전달하는 방법입니다. 간단한 쿼리에서 불필요한 클래스 생성을 줄일 수 있습니다.
언제 사용하나요?
- 간단한 조회에서 2-3개 파라미터 전달
- DTO 클래스 생성이 과한 경우
- 페이징 처리 (offset, limit)
- 범위 검색 (startDate, endDate)
방법 1: @Param 어노테이션 (권장)
// Mapper 인터페이스
@Mapper
public interface UserMapper {
// 단일 파라미터는 @Param 생략 가능
User findById(Long id);
// 2개 이상은 @Param 필수
User findByEmailAndStatus(
@Param("email") String email,
@Param("status") String status
);
// 페이징
List<User> findAllWithPaging(
@Param("offset") int offset,
@Param("limit") int limit
);
// 날짜 범위
List<Order> findByDateRange(
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate,
@Param("status") String status
);
}
XML Mapper에서 사용
<!-- @Param으로 지정한 이름 그대로 사용 -->
<select id="findByEmailAndStatus" resultType="User">
SELECT * FROM users
WHERE email = #{email}
AND status = #{status}
</select>
<!-- 페이징 -->
<select id="findAllWithPaging" resultType="User">
SELECT * FROM users
ORDER BY created_at DESC
LIMIT #{limit} OFFSET #{offset}
</select>
<!-- 조건부 파라미터 -->
<select id="findByDateRange" resultType="Order">
SELECT * FROM orders
WHERE 1=1
<if test="startDate != null">
AND order_date >= #{startDate}
</if>
<if test="endDate != null">
AND order_date <= #{endDate}
</if>
<if test="status != null and status != '">
AND status = #{status}
</if>
</select>
방법 2: param1, param2 사용
// @Param 없이 순서로 접근
List<User> findByAgeRange(int minAge, int maxAge);
<!-- XML에서 param1, param2로 접근 -->
<select id="findByAgeRange" resultType="User">
SELECT * FROM users
WHERE age BETWEEN #{param1} AND #{param2}
</select>
<!-- 또는 arg0, arg1 (비권장) -->
<select id="findByAgeRange" resultType="User">
SELECT * FROM users
WHERE age BETWEEN #{arg0} AND #{arg1}
</select>
<!-- param1, param2는 가독성이 낮아 @Param 권장 -->
방법 3: Map 사용
// Map으로 전달
List<User> findByConditions(Map<String, Object> params);
// 호출
Map<String, Object> params = new HashMap<>();
params.put("status", "ACTIVE");
params.put("minAge", 20);
params.put("maxAge", 30);
List<User> users = mapper.findByConditions(params);
<!-- XML -->
<select id="findByConditions" resultType="User">
SELECT * FROM users
WHERE status = #{status}
AND age BETWEEN #{minAge} AND #{maxAge}
</select>
INSERT/UPDATE에서 사용
// 여러 파라미터로 UPDATE
int updateStatus(
@Param("id") Long id,
@Param("status") String status,
@Param("updatedBy") String updatedBy
);
<update id="updateStatus">
UPDATE users
SET status = #{status},
updated_by = #{updatedBy},
updated_at = NOW()
WHERE id = #{id}
</update>
// 조건부 INSERT
int insertIfNotExists(
@Param("email") String email,
@Param("name") String name
);
복잡한 조건 처리
<!-- 동적 IN 절 -->
List<User> findByIds(@Param("ids") List<Long> ids);
<select id="findByIds" resultType="User">
SELECT * FROM users
WHERE id IN
<foreach collection="ids" item="id"
open="(" separator="," close=")">
#{id}
</foreach>
</select>
<!-- 여러 파라미터 + 리스트 -->
List<Order> findOrders(
@Param("userId") Long userId,
@Param("statuses") List<String> statuses
);
<select id="findOrders" resultType="Order">
SELECT * FROM orders
WHERE user_id = #{userId}
AND status IN
<foreach collection="statuses" item="status"
open="(" separator="," close=")">
#{status}
</foreach>
</select>
주의사항
- 파라미터가 3개 이상이면 DTO 클래스 권장
- @Param 이름과 XML 변수명 정확히 일치해야 함
- null 값 처리를 위한 조건문 추가 필요
- MyBatis 3.x 이상에서 @Param 사용 가능