Mapper 생성

Mapper 생성

Mapper는 myBatis에서 실행할 SQL 구문을 가지는 파일이다. Spring Boot 설정파일에서 설정한 경로는 다음과 같다

  • /mybatis/mapper/**/*-mapper.xml

해당 경로는 classpath를 기준으로 하기 때문에 src/main/resources 내부에 작성한다.

+-- src/main/resource
    +-- mybatis
        +-- mapper
            +-- student-mapper.xml

mapper 폴더 내부에 작성된 -mapper.xml로 끝나는 파일이라면 모두 불러오도록 설정하였다. mapper 파일을 생성할 때 구분을 위해 테이블명을 접두사로 붙여 생성한다.

student-mapper.xml

student-mapper.xml의 기본 형태는 다음과 같다.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="student">
    
</mapper>

DOCTYPE 설정을 통해 mybatis-3-mapper.dtd 형식을 문서에 적용한다.

Mapper 파일의 모든 내용은 <mapper> 내부에 작성하며, namespace에는 외부에서 호출할 수 있도록 중복되지 않은 식별자를 작성한다. 테이블명으로 작성할 경우 중복이 발생하지 않으므로 예시 파일에서는 테이블 이름인 student로 작성하였다.

생성한 Mapper 파일 내부에 INSERT, SELECT, UPDATE, DELETE 구문을 배치하여 데이터베이스 작업을 처리할 수 있도록 구현한다.

Entity 클래스 생성

student 테이블을 자바와 연동하기 위한 Entity 클래스를 생성한다. Spring JDBC와 동일하게 StudentDto로 생성한다.

Spring Boot 설정에서 지정한 패키지에 클래스를 생성해야 myBatis에서 사용할 수 있다.

package com.hacademy.boot07.entity;

//코드 간소화를 위해 Lombok 사용
@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class StudentDto {
    private int no;
    private String name;
    private int korean, english, math;
}

INSERT TEST

spring-boot-test를 사용하여 해당 테이블에 INSERT를 수행하는 테스트를 작성한다.

student-mapper.xml
<insert id="add" parameterType="StudentDto">
    INSERT INTO STUDENT(
        NO, NAME, KOREAN, ENGLISH, MATH
    )
    VALUES(
        STUDENT_SEQ.NEXTVAL, 
        #{name}, 
        #{korean}, 
        #{english}, 
        #{math}
    )
</insert>

INSERT는 Mapper 파일에서 <insert> 태그에 작성하며, parameterType 속성에는 구문 실행을 위해 필요한 데이터의 자료형을 설정한다. application.properties에 패키지를 등록하였거나 mybatis에서 관리되는 클래스의 경우 경로를 생략하거나 설정한 별칭을 사용할 수 있다.

작성하는 SQL 구문에는 샵#과 중괄호{}를 사용하여 parameterType으로 지정한 데이터의 속성을 추출할 수 있다.

  • #{name}은 StudentDto 객체의 name 필드를 추출한다

  • #{korean}은 StudentDto 객체의 korean 필드를 추출한다

  • #{english}는 StudentDto 객체의 english 필드를 추출한다

  • #{math}는 StudentDto 객체의 math 필드를 추출한다

StudentInsertTest.java
package com.hacademy.boot07;

@SpringBootTest
public class StudentInsertTest {

	@Autowired
	private SqlSession sqlSession;
	
	@Test
	public void test() {
		StudentDto studentDto = StudentDto.builder()
			.name("피카츄").korean(60).english(70).math(80)
			.build();
		sqlSession.insert("student.add", studentDto);
	}
	
}

테스트 과정을 그림으로 나타내면 다음과 같다.

SELECT TEST

SELECT의 경우 다음과 같이 구분된다.

  • 단건 조회

  • 다건 조회

단건 조회 구문은 PK를 이용하여 다음과 같은 형태이다.

SELECT * FROM STUDENT [PRIMARY KEY 조건]

다건 조회 구문은 다음과 같은 형태이다.

SELECT * FROM STUDENT [조건] [정렬] [그룹]

다건 조회

student-mapper.xml
<select id="list" resultType="StudentDto">
    SELECT * FROM STUDENT
</select>

조회의 경우 <select> 태그를 사용하며 반드시 resultType 속성을 가져야 한다. 구문 완성에 필요한 값이 있다면 parameterType을 가질 수 있다. resultType에는 구문이 실행된 뒤 매핑될 객체의 자료형을 작성하는데, 목록의 경우 자바에서 실제로 List<StudentDto>라는 형태가 필요하지만 myBatis는 StudentDto로 매핑되어야 한다는 사실만 알면 되기 때문에 List가 아닌 StudentDto를 작성한다.

StudentListTest.java
package com.hacademy.boot07;

@SpringBootTest
public class StudentListTest {

    @Autowired
    private SqlSession sqlSession;
    
    @Test
    public void test() {
        List<StudentDto> list = sqlSession.selectList("student.list");
        System.out.println("데이터 개수 : " + list.size());
        for(StudentDto studentDto : list) {
            System.out.println(studentDto);
        }
    }

}

자바 코드에서는 SqlSession을 통해 구문을 호출하며, namespace명과 구문 ID를 통해 호출한다. 전달할 데이터가 없으므로 구문 정보만 작성하였다. 조회 결과는 List<StudentDto>로 받아서 사용 가능하며, 결과에 대한 매핑은 myBatis가 자동으로 수행하며 없는 경우에도 null이 아닌 List가 반환된다.

단건 조회

Primary Key를 사용한 단건 조회를 하기 위하여 필요한 코드는 다음과 같다.

<select id="detail" resultType="StudentDto" parameterType="int">
    SELECT * FROM STUDENT WHERE NO = #{no}
</select>

조회이므로 <select> 태그를 사용하고 resultType은 조회한 결과를 매핑하기 위한 형태인 StudentDto를 사용한다. parameterType에는 구문을 실행하기 위하여 필요한 번호(no)의 형태를 작성한다. int와 같이 Java에서 기본적으로 제공하는 형태이거나 Collection처럼 자주 쓰이는 형태들은 myBatis에서 미리 별칭으로 등록해두었다. 다음 링크에서 확인할 수 있다.

StudentDetailTest.java
package com.hacademy.boot07;

@SpringBootTest
public class StudentDetailTest {

	@Autowired
	private SqlSession sqlSession;

	@Test
	public void test() {
		int no = 1;
		StudentDto studentDto = sqlSession.selectOne("student.detail", no);
		System.out.println(studentDto);
	}
	
}

테스트 코드에서는 번호를 통해 student.detail 구문을 호출할 수 있도록 SqlSession을 사용하여 selectOne 메소드를 호출해준다. selectOne 명령은 결과 집합의 행 개수가 0 또는 1일 경우 사용하므로 목록에서 사용하지 않도록 주의해야 한다.

번호에 대한 결과가 존재하지 않는다면 null이 반환되고, 결과가 존재한다면 StudentDto 객체가 반환된다.

count, sum, avg, min, max 등 집계 함수를 사용하는 경우도 단건 조회에 해당한다.

UPDATE TEST

번호를 이용해서 나머지 정보(이름, 점수)를 변경하도록 구현하는 것이 가장 기본적인 수정 구문이다. 다음과 같이 매퍼와 테스트 코드를 작성한다.

student-mapper.xml
<update id="edit" parameterType="StudentDto">
    UPDATE STUDENT
        SET 
            NAME = #{name},
            KOREAN = #{korean},
            ENGLISH = #{english},
            MATH = #{math}
        WHERE 
            NO = #{no}
</update>

매퍼 파일에는 <update> 태그로 구문을 작성하며, parameterType에는 총 5가지 정보를 전달받을 수 있도록 StudentDto를 선언한다. 주의할 점은 resultType을 가질 수 없다는 것이다.

StudentEditTest.java
package com.hacademy.boot07;

@SpringBootTest
public class StudentEditTest {
	
	@Autowired
	private SqlSession sqlSession;

	@Test
	public void test() {
		StudentDto studentDto = StudentDto.builder()
			.no(1)
			.name("피카츄")
			.korean(70)
			.english(60)
			.math(50)
			.build();
		int count = sqlSession.update("student.edit", studentDto);
		System.out.println(count);
	}

}

테스트에서는 SqlSession의 update 메소드를 사용하여 구문을 호출하며, 구문을 완성시킬 수 있도록 StudentDto 객체를 파라미터로 전달해야 한다. UPDATE 구문은 실행 후 변경된 행의 개수를 반환하므로 int 형태로 저장하여 성공과 실패 여부를 판정하여 추가 로직을 작성할 수 있다.

if(count > 0){
	//변경된 대상이 있는 경우
}
else {
	//변경된 대상이 없는 경우 
}

DELETE TEST

삭제는 기본키(Primary key)인 번호(no)를 이용하여 하나의 대상을 삭제하는 것이 가장 기본적인 구문이다. 다음과 같이 매퍼와 테스트 코드를 작성한다.

<delete id="delete" parameterType="int">
	DELETE STUDENT WHERE NO = #{no}
</delete>

매퍼 파일에는 <delete> 태그로 구문을 작성하며, parameterType에는 삭제를 위한 기본키인 번호(no)의 자료형 int를 작성한다. resultType은 작성할 수 없으므로 주의해야 한다.

package com.hacademy.boot07;

@SpringBootTest
public class StudentDeleteTest {

	@Autowired
	private SqlSession sqlSession;
	
	@Test
	public void test() {
		int no = 1;
		int count = sqlSession.delete("student.delete", no);
		System.out.println(count);
	}
	
}

테스트에서는 번호(no)를 미리 정하고 SqlSession의 delete 메소드를 사용하여 구문을 호출한다. 구문의 완성을 위해 번호를 전달한다. DELETE 구문은 UPDATE와 같이 실행 후 변경된 행의 개수를 반환하므로 int 형태로 결과를 저장하여 성공과 실패 시 추가 로직을 작성하는 데 활용할 수 있다.

if(count > 0){
	//삭제된 대상이 있는 경우(성공)
}
else {
	//삭제된 대상이 없는 경우(실패)
}

정리

이 문서의 내용을 요약하면 다음과 같다.

  • application.properties에 mybatis 설정을 해야 한다

  • mapper 파일을 만들어 실행할 SQL 구문을 보관한다

    • <insert>는 등록 시 사용하며, parameterType을 가질 수 있다.

    • <select>는 조회 시 사용하며, parameterTyperesultType을 가질 수 있다.

      • 다건 조회는 selectList 메소드를 사용한다

      • 단건 조회는 selectOne 메소드를 사용한다

    • <update>는 수정 시 사용하며, parameterType을 가질 수 있고 결과 행 수를 반환한다.

    • <delete>는 삭제 시 사용하며, parameterType을 가질 수 있고 결과 행 수를 반환한다.

Last updated