본문 바로가기
Framework/MyBatis

[01] Mybatis의 CRUD 방식

by 예스p 2023. 2. 13.

변화되는 프로세스

이전 레거시방식에서는 사용자의 요청을 처리하기 위해

jsp(화면단) > Controller(서블릿클래스) > Service(클래스) > Dao(클래스) > mapper(xml) 의 로직을 거쳤다.

Mybatis를 사용했을때도 기본 로직은 동일하나 조금씩 변화되는 코드들이 있다.


Controller에서 달라지는 부분

  • sql문이 전달받을 수 있는 객체는 1개이기 때문에(페이징용 제외) 데이터가 단 2개라 하더라도 한곳에 담아야 한다.
    이런 경우 vo클래스를 만들수도 있지만 보다 간결하게 HashMap을 활용할수도 있다.
    >>mapper단에서는 #{키값}으로 뽑으면 된다.
	//Vo객체 대신 활용할 수 있는 HashMap
	HashMap<String, String> map = new HashMap<>();
	map.put("condition", condition);
	map.put("keyword", keyword);

 

 

Service에서 달라지는 부분

  • 이전 JDBC 방식에서는 Dao의 기본생성자에 Properties객체와 sql문이 작성된 mapper.xml 파일을 연결시키는 구문을 작성했었다.
    >>Service단에서는 매번 새로이 new Dao()를 생성 했어야만 했다.
  • Mybatis방식에서는 SqlSession객체를 만드는 행위에 mapper.xml을 연결시키는 과정이 녹아있다.
    >> Dao객체를 전역변수로 선언해놓을 수 있다!
  • SqlSession 객체는 Connection 객체의 역할을 대신할 뿐 만 아니라 자체적으로 가지고 있는 commit(), rollback(), close() 메소드를 활용할 수 있다.
    Template를 static import하여 객체 생성 메소드를 바로 사용할 수 있도록 한다.
  • Sql객체가 생성될때 mybatis-config가 읽어들여지고, mapper파일이 읽어들여다.
//Service를 Interface로 설계한 후 구현하는 연습을 해본다.
public class MemberServiceImpl implements MemberService {
    //실시간으로 생성할 필요가 없어 전역변수로 선언해놓는다.
    private MemberDao mDao = new MemberDao();
   
    @Override 
    public int insertMember(Member m) {
        SqlSession sqlSession = getSqlSession();
        int result = mDao.insertMember(sqlSession, m);
        if(result>0) {
            sqlSession.commit(); //자체적으로 메소드를 가지고 있다.
        }else {
            sqlSession.rollback();
        }
        sqlSession.close();
        return result;
    }
...
}

 

 

Dao에서 달라지는 부분

  • 전달받은 SqlSession 객체가 가지고 있는 sql 전용 메소드를 통해서 sql문을 완성시키고 결과를 객체로 돌려 받는다.
    [표현법] SqlSession객체.sql에따른메소드("sql문지정"[, 전달할 객체, Rowbounds]) 
  • 메소드의 종류 
    객체.insert(...) : insert문 전용 메소드
    객체.update(...) : update문 전용 메소드
    객체.delete(...) : delete문 전용 메소드
    객체.selectOne(...) : 1개행만 돌려받는 쿼리문일 경우 사용한다.
    객체.selectList(...) :
       -여러행을 돌려받는 쿼리문일 경우 사용한다.
       -유일하게 매개변수 3개짜리가 있다.
       -리턴은 List이기때문에 (ArrayList)를 앞에 붙여 다운캐스팅 해주어야한다.
  • 매개변수의 순서
    1. 첫번째 매개변수 : " 매퍼파일의별칭 . sql문의 id "
    2. 두번째 매개변수 : 해당 sql문을 완성시킬 객체
        만약 완성형태의 sql문일경우 생략할 수 있다.
        세번째 매개변수를 써야한다면 null을 입력한다. 
    3. 세번째 매개변수 : RowBounds객체
        selectList 메소드에서 활용할 수 있다.
public int insertMember(SqlSession sqlSession, Member m) {
    return sqlSession.insert("memberMapper.insertMember", m);
}

 

 


sql을 저장할 mapper.xml

Mybatis에서 mapper.xml는 중요한 역할을 한다.

mapper.xml을 만들고 등록하는 과정을 알아본다.


sql을 위한 xml파일 만들기

  • 생성위치 : resources(소스폴더)/mappers/member-mapper.xml
  • <!DOCTYPE>
    : 문서형식을 선언하는 태그로 mybatis전용 구문이 있다.
    공식사이트에서 복붙해온다.
  • <mapper>
    : 해당 파일의 정체성은 mapper이다. mapper태그로 전체 내용을 감싸준다.
    - namespace 속성:  
      mapper파일의 id를 지정한다. (필수)
      id는 mapper파일을 mybatis-config에 등록할때 쓰인다.
  • <select>  <insert>  <update>  <delete>
    : sql문들은 자신의 키워드에 맞는 태그를 기술한 후 content부에 sql문을 작성하면 된다.
    - 이전 JDBC방식에서 ?로 미완성된 sql문을 작성했다면, Mybatis방식에서는 객체를 전달받는다는것을 전제로 sql문을 완성시킨다.
    값을 넣을 때는 다음과 같은 두가지 방법이 있다.
    1. #{필드명or변수명or키값}
      - 해당 위치에 ?가 생기며 파싱되며, PreparedStatement를 생성하게 된다. 
      >>재활용(캐싱)되기 때문에 효율적이다.
      - ' '가 붙으며 쿼리가 수행되나 오라클은 숫자-문자간에 자동형변환이 지원되기때문에 문제되지 않는다
    2. ${필드명or변수명or키값}
      - 값이 넣어진채로 쿼리문이 수행된다(파라미터의 값이 바뀔때마다 쿼리문 파싱을 진행해야한다는 단점)
      - 작은따옴표가 붙지 않아 테이블이름이나 컬럼이름을 동적으로 결정할 때 활용할 수 있다.
      - SQL Injection에 취약하다는 보안적 단점이 있다.
      (입력값으로 서버의 데이터베이스를 공격하는 것)
    >> 두 방법 모두 내부적으로 getter메소드가 실행되기 때문에 메소드는 필수이다.
    - id 속성 : 
      각각의 sql문을 식별할 수 있는 아이디를 지정해준다.
      관례대로 해당 sql문이 쓰일 메소드명과 일치시켜준다.
    - parameterType 속성 : 
      statement에 사용되기 위해 전달받을 객체나 자료형의 풀클래스명 혹은 별칭 기술한다.
    ** 기본자료형이나 자바내장객체의 경우 MyBatis에서 지정해놓은 별칭을 쓰면 된다.
      ( 공식사이트 - [매퍼설정] - typeAliases부분에서 다양한 별칭을 확인할 수 있다.)
      마이바티스가 자동계산 가능하므로 생략 가능
  • <select>의 결과타입 속성 : 
    - Mybatis는 매핑(조회된 칼럼값 뽑아서 자바객체에 담는 것)이 자동으로 진행된다.
    이때 어떤 타입으로 돌려줄건지 resultType 혹은 resultMap 속성으로 기재해주어야 한다.
    - resultType 속성 : 자바의 타입(풀클래스명or별칭)을 입력한다.
      vo객체의 경우 컬럼명과 필드명이 일치할 경우만 사용할 수 있다.
      단, select문의 칼럼에 필드명과 일치하도록 별칭을 넣었다면 컬럼명과 필드명이 달라도 사용 할 수 있다.
    - resultMap 속성 : 매핑시킬 resultMap의 id를 입력한다.
  • <resultMap>
    -컬럼명과 필드명이 일치하지 않는 경우 어떤컬럼의 값을 어떤 필드에 입력시킬건지 매칭을 시켜준다.
    -보통 mapper상단에 기재한다.
    [표현법]
    <resultMap id="식별자" type="vo객체풀클래스명or별">
        <id colume="db칼럼명" property="vo필드명" />
        <result column="db칼럼명" property="vo필드명" />
        ....
    </resultMap>
    - primaryKey는 id 태그를 쓸 수 있음.(심화활용에 쓰임)
    - column은 대소문자를 가리지 않으나 property는 대소문자를 구분한다.
    - column은 출력되는 컬럼 그 자체를 인식하므로 r.create_date 등과 같이 테이블별칭을 붙여준 경우라도 create_date로 입력해야한다.
<?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="memberMapper">
    <!-- resultMap을 지정하는 예시 -->
    <resultMap id="memberResultSet" type="com.br.mybatis.member.model.vo.Member">
        <result column="user_no" property="userNo" />
        ...
        <result column="status" property="status" />
    </resultMap>
...
    <!-- 다양한 sql문들을 입력하는 예시 -->
	<insert id="insertMember" parameterType="com.br.mybatis.member.model.vo.Member">
		insert
		  into member
		  ...
	</insert>
    <select id="loginMember" parameterType="Member" resultMap="memberResultSet">
        select *
          from member
          ...
    </select>    
...
</mapper>

 

 

mapper.xml등록하기

  • Dao에서 sql을 찾을 수 있도록 mapper.xml을 등록해주어야 한다.
  • 등록할 위치는 resources(소스폴더)/config/mybatis-config.xml의
    <mappers>태그 안에 등록한다.
<mappers>
    <mapper resource="/mappers/member-mapper.xml" />
    <mapper resource="/mappers/board-mapper.xml" />
    ...
</mappers>

 

 

 

 

 

이미지 출처 instagram @teaaalexis

댓글