-
[MyBatis] 매퍼 xml파일과 매퍼 인터페이스를 사용한 CRUDJAVA 2022. 7. 24. 23:16
먼저 테이블이 있어야 하므로, 다음과 같은 컬럼과 값을 가진 tbl_member 테이블을 생성한다.
CREATE TABLE tbl_member( userid varchar2(50) not null primary key, userpw varchar2(100) not null, username varchar2(100) not null, regdate date default sysdate, updatedate date default sysdate, enabled char(1) default '1');
그리고 도메인 패키지에 UserVO 클래스를 만들고 다룰 데이터들을 필드로 지정했다.
package org.zerock.myapp.domain; import lombok.Value; @Value public class UserVO { private String userid; private String userpw; private String username; } // end class
1. xml파일
src/main/resources에 mappers패키지를 만들고 UserMapper.xml 파일을 생성했다.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="mappers.UserMapper"> <insert id="insertNewUser"> INSERT INTO tbl_member (userid, userpw, username) VALUES ( #{userid}, #{userpw}, #{username} ) </insert> </mapper>
상단의 DOCTYPE mapper는 반드시 있어야 한다.
namespace에 이름을 지정하고, select / insert / delete / update 태그에 각각 SQL문을 작성한다.
보통 관례상 namespace는 패키지명.파일명으로 설정하고, id는 SQL문을 수행시킬 메소드 이름으로 정한다.
네임 스페이스가 다르면 아이디가 중복되어도 된다.
#{}은 메소드 수행시 직접 값을 넣어줄 때 사용한다. 이름은 마음대로 지정해도 되지만, 열이름으로 작성하는 것이 좋다.
@Test @Order(4) @DisplayName("insertNewUser") @Timeout(value = 10, unit = TimeUnit.SECONDS) void insertNewUser() { log.trace("insertNewUser() invoked."); SqlSession sqlSession = this.sqlSessionFactory.openSession(false); // SET AUTOCOMMIT OFF try(sqlSession;) { String namespace = "mappers.UserMapper"; String sqlId = "insertNewUser"; String sql = new StringBuffer() .append(namespace) .append(".") .append(sqlId) .toString(); for(int i=1; i<=10; i++) { Map<String, Object> params = new HashMap<>(); params.put("userid", "USER_"+i); params.put("userpw", "PASS_"+i); params.put("username", "NAME_"+i); // Map 객체를 파라미터로 전달하면서 Mapped Statement 수행(DML) int insertedRows = sqlSession.insert(sql, params); log.info("\t+ insertedRows: {}", insertedRows); } // for sqlSession.commit(); // TCL : ALL or Nothing log.info("\t+ Commited."); } catch(Exception e) { sqlSession.rollback(); // TCL : All or Nothing log.info("\t+ Rolled back."); throw e; } // try-with-resources } // insertNewUser
메소드를 실행하는 테스트코드를 만들었다.
namespace.id 형식으로 이름을 만들어서 주면 마이바티스가 경로를 찾은 후 해당하는 SQL문을 실행한다.
sqlSession의 insert메소드의 두번째 매개변수로 맵객체를 만들어서 주면 #{}안에 입력한 이름과 일치하는 키를 찾아 값으로 넣어준다. 맵객체를 넣어도 되고, 자바빈즈 클래스를 넣어줄 수도 있다. 클래스는 따로 만들어야하기 때문에, 맵객체를 이용하는게 더 간편해보인다.
DML문장을 수행할땐 오토커밋을 해제하고 직접 커밋 또는 롤백을 결정하는게 좋다. try-catch블록을 사용해서 오류가 발생했을 경우 rollback하도록 작성했다.
메소드를 실행하면 데이터가 잘 들어온 것을 확인할 수 있다.
2. 인터페이스
매퍼 xml파일 대신 인터페이스로도 SQL문장을 매핑할 수 있다. 이때 마이바티스의 어노테이션을 이용한다.
package org.zerock.myapp.mapper; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.zerock.myapp.domain.UserVO; public interface UserMapper { @Select( "SELECT userid, userpw, username " + "FROM tbl_member " + "WHERE userid > #{userid} AND username > #{username}") public abstract List<UserVO> selectUsers( @Param("userid") String userid, @Param("username") String username); @Insert( "INSERT INTO tbl_member " + "(userid, userpw, username) " + "VALUES (#{userid}, #{userpw}, #{username})") public abstract int insertUser( @Param("userid") String userid, @Param("userpw") String userpw, @Param("username") String username); @Delete("DELETE FROM tbl_member WHERE userid = #{userid}") public abstract int deleteUser(@Param("userid") String userid); } // end interface
추상 메소드를 만들고, 어노테이션 안에 SQL문을 작성한다.
DML, DQL문장별 어노테이션이 존재한다. 직접 값을 입력하고 싶을 땐 xml파일과 마찬가지로 #{}문법을 사용한다.
#{}을 사용했을 땐 메소드 수행시 값을 파라미터로 넘겨줄 수 있도록 매개변수를 만들어준다. 이 때 @Param어노테이션을 사용한다. @Param 속성으로 #{}안에 작성한 이름을 지정하면 해당 매개변수를 값으로 넣어준다.
@Test void 인터페이스를사용한방식() { log.trace("인터페이스를사용한방식() invoked."); SqlSession sqlSession = this.sqlSessionFactory.openSession(); // Mapper Interface를 이용하여 SQL 문장처리 try(sqlSession;) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); assertNotNull(mapper); mapper.selectUsers("USER_3", "NAME_4"); mapper.insertUser("홍길동", "1234", "닉네임"); mapper.deleteUser("홍길동"); } // try-with-resources } // 인터페이스를사용한방식
SqlSession클래스의 .getMapper()메소드를 사용해 매퍼를 얻어준다. 작성한 인터페이스를 매개변수로 지정해야 하는데, clazz객체를 요구하기 때문에 클래스 객체로 넣어준다.
그 후 내장된 메소드를 각각 호출하면 알아서 SQL문장에 파라미터를 넘기고 수행한다.
DriverSpy를 사용했기 때문에 로그를 찍지 않아도 상세하게 알려준다.
정상적으로 조회, 삽입, 삭제가 된 모습이다.
간단한 SQL문장을 실행할 땐 인터페이스 방식이 간편하고, 복잡한 쿼리문을 수행할 땐 xml파일을 이용하는 것이 좋다.
'JAVA' 카테고리의 다른 글
[MyBatis] 마이바티스란? 메이븐 프로젝트에서 마이바티스 설정하기 (0) 2022.07.24 [JAVA] JUnit5를 이용해 테스트 코드를 작성해보자! (0) 2022.07.23 [Servlet] 파일업로드시 현재날짜로 디렉토리 생성하기, UUID로 파일명 저장하기 (0) 2022.07.14 [Servlet] Scope 단위 (Application, Session, Request, Page) (0) 2022.07.12 [Servlet] 포워딩(Forward)과 리다이렉트(Redirect) (0) 2022.07.11