2020-11-11 TIL

7 minute read

MyBatis

도입

Data Persistence Framework => 데이터의 영속성(지속성; 등록,조회,변경,삭제)을 대신 처리해주는 프레임워크. 1) SQL Mapper

  • 직접 SQL 문을 작성
  • 각각의 DBMS에 최적화된 SQL을 작성할 수 있다.
  • DBMS마다 미미하게 다른 SQL을 작성해야 하는 번거로움이 있다.
  • 예) Mybatis 등 2) OR Mapper
  • 전용언어 및 문법(Domain-Specific Language;DSL)을 사용하여 작성 실행할 때 DBMS에 맞춰서 SQL을 생성하여 실행한다.
  • DBMS에 마다 SQL문을 작성할 필요가 없어 편리하다.
  • DBMS에 최적화된 SQL을 실행할 수 없다. 즉 DBMS의 특징을 최대로 활용할 수 없다.
  • 예) Hibernate, TopLink 등

Mybatis 도입 1) 의존 라이브러리 추가

  • mvnrepository.com 검색하여 build.gradle 파일에 추가한다.
  • “gradle eclipse” 실행한 후 이클립스 에디터에서 프로젝트를 “refresh” 한다. 2) mybatis 설정 파일 준비
  • mybatis-config.xml 생성 및 편집 3) DB 연결 정보를 담은 프로퍼티 파일 준비
  • jdbc.properties 생성 및 편집 4) SQL 문장을 작성할 파일 준비
  • BoardMapper.xml 생성 및 편집 5) Mybatis 객체 준비
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <!-- jdbc.properties 파일의 내용을 읽어온다.
       읽어온 정보는 ${프로퍼티명} 문법을 이용하여  값을 사용할  있다. -->
  <properties resource="com/eomcs/mybatis/ex01/jdbc.properties"></properties>

  <!-- DBMS에 연결할  사용할 정보를 설정한다.
       여러 개의 연결 정보를 설정해두고  중에 사용할 정보를 지정할  있다.
       default="development" 의미는, 
       여러 연결 정보 중에서 "development"라는 연결 정보를 사용하여 실행하겠다는 의미다. -->
  <environments default="development">
    
    <!-- 각각의 연결 정보는 다음과 같이 environment 태그에 설정한다. -->   
    <environment id="development">
    
      <!-- 트랜잭션 관리 방식을 지정한다. -->
      <transactionManager type="JDBC"/>

      <!-- DB 커넥션 풀에 관련된 정보와 DB 연결 정보를 설정한다. 
           이제 개발자가 DB 커넥션 풀을 다룰 필요가 없다.
           mybatis 프레임워크에서 관리한다. -->
      <dataSource type="POOLED">
        <!-- ${위의 .properties 파일에 저장된 프로퍼티명} -->
        <property name="driver" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
      </dataSource>
    </environment>
  </environments>
  
  <!-- SQL문을 모아둔 파일(SQL 맵퍼 파일이라 부른다) 지정한다.
       SQL 맵퍼 파일에 작성해  SQL문을 mybatis가 사용할 것이다. -->
  <mappers>
    <!-- 맵퍼 파일의 경로를 지정할  classpath 경로를 사용해야 한다.
          패키지명을 구분할  '.' 대신에 '/' 사용해야 한다. -->
    <mapper resource="com/eomcs/mybatis/ex01/BoardMapper.xml"/>
  </mappers>
</configuration>

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    // 1. mybatis 설정 파일을 읽을 InputStream 도구를 준비한다.
    // 1) 직접 파일 시스템 경로를 지정하기
    // => 단 소스 파일 경로를 지정하지 말아라.
    // => 컴파일된 후 XML 파일이 놓이는 경로를 지정해라.
    // => 자바 패키지에 작성한 일반 파일은 그대로 빌드 디렉토리에 복사된다.
    // => 예) 프로젝트폴더/bin/main/com/eomcs/mybatis/ex01/mybatis-config.xml
    //
    InputStream mybatisConfigInputStream = new FileInputStream(//
        "./bin/main/com/eomcs/mybatis/ex01/mybatis-config.xml");

    // 2. SqlSessionFactory를 만들어 줄 빌더 객체 준비
    //
    SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();

    // 3. SqlSession 객체를 만들어 줄 팩토리 객체 준비
    // => mybatis는 Builder를 이용하여 SqlSessionFactory 객체를 만든다.
    // => 이때 공장 객체를 만들 때 사용할 설정 파일을 지정한다.
    // => 설정 파일의 경로를 직접 지정하지 말고,
    // 해당 파일을 읽을 때 사용할 InputStream을 넘겨줘라.
    //
    SqlSessionFactory factory = factoryBuilder.build(mybatisConfigInputStream);

    // 4. SQL을 실행시키는 객체 준비
    // => SqlSessionFactory 객체로부터 SqlSession 객체를 얻는다.
    // => openSession()은 수동 커밋으로 SQL을 다루는 객체를 리턴한다.
    // => 자동 커밋으로 SQL을 다루고 싶다면,
    // openSession(boolean autoCommit) 메서드를 호출하라.
    //
    SqlSession sqlSession = factory.openSession();

    System.out.println("mybatis 준비 완료!");

    sqlSession.close();
  }

}

 public static void main(String[] args) throws Exception {
    // 1. mybatis 설정 파일을 읽을 InputStream 도구를 준비한다.
    // => 다음과 같이 mybatis 설정 파일의 경로를 직접 지정하면
    // 애플리케이션 배포 경로가 바뀔 때 마다
    // 소스를 변경하고 다시 컴파일 해야 하는 문제가 있다.
    // InputStream mybatisConfigInputStream = new FileInputStream(//
    // "./bin/main/com/eomcs/mybatis/ex01/mybatis-config.xml");

    // => 이를 간편하게 하기 위해 Mybatis는 도우미 객체를 제공한다.
    // => Resources 클래스의 메서드를 이용하면
    // 자바 클래스가 있는 패키지 폴더에서 mybatis 설정 파일을 찾을 수 있다.
    //
    InputStream mybatisConfigInputStream = Resources.getResourceAsStream(//
        "com/eomcs/mybatis/ex01/mybatis-config.xml");
    // => 파라미터에 mybatis 설정 파일의 경로를 지정할 때,
    // 자바 패키지 경로를 그대로 이용한다.
    // => 단 파일 경로이기 때문에 폴더와 폴더 사이를 가리킬 때
    // . 대신에 / 를 사용해야 한다.
    // => JVM은 현재 실행하는 애플리케이션의 자바 클래스 경로를 알고 있다.
    // => 주의!
    // 자바 패키지 경로에서 찾기 때문에 mybatis 설정 파일은 반드시
    // 자바 패키지 경로에 있어야 하다.
    //

    SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();

    SqlSessionFactory factory = factoryBuilder.build(mybatisConfigInputStream);

    SqlSession sqlSession = factory.openSession();

    System.out.println("mybatis 준비 완료!");

    sqlSession.close();
  }

}
public static void main(String[] args) throws Exception {
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(//
        Resources.getResourceAsStream(//
            "com/eomcs/mybatis/ex01/mybatis-config.xml"));
    
    SqlSession sqlSession = factory.openSession();

    // SqlSession 객체를 이용하여 SQL 맵퍼 파일에 작성한 SQL 문을 실행한다.
    // => select 문장 
    //    - sqlSession.selectList() : 목록 리턴
    //    - sqlSession.selectOne() : 한 개의 결과 리턴
    // => insert 문장
    //    - sqlSession.insert() 
    // => update 문장
    //    - sqlSession.update()
    // => delete 문장
    //    - sqlSession.delete()
    // => insert/update/delete인 경우 insert()/update()/delete() 메서드 중
    //    아무거나 호출해도 된다. 
    //    하지만 일관된 유지보수를 위해 메서드를 구분하여 사용하라!
    // 
    // 메서드 사용법)
    // => 예) selectList(SQL문 식별자, 파라미터값)
    //    - SQL문 식별자 = 그룹명 + "." + SQL문장 아이디
    //      - 그룹명: <mapper namespace="그룹명">...</mapper>
    //      - SQL 문장 아이디: <select id="SQL문장 아이디">...</select>
    //    - 파라미터 값: primitive type 및 모든 자바 객체가 가능하다. 
    //                 여러 개의 값을 전달할 때는 Map에 담아 넘겨라!
    List<Board> list = 
        sqlSession.selectList("BoardMapper.selectBoard");

    for (Board board : list) {
      System.out.printf("%d, %s, %s, %s, %d\n", 
          board.getNo(), 
          board.getTitle(), 
          board.getContent(),
          board.getRegisteredDate(),
          board.getViewCount());
    }
    sqlSession.close();
  }
}

// selectList() 동작 원리
// ---------------------------------------------------------------------
// <select id="selectBoard" resultType="com.eomcs.mybatis.ex01.Board">
// select 
//   board_id,
//   title,
//   contents,
//   created_date,
//   view_count
// from x_board
// </select>
//---------------------------------------------------------------------
// => resultType 에 지정한 클래스의 인스턴스를 생성한다.
// => 컬럼 이름과 일치하는 프로퍼티를 찾아 값을 입력한다.
//    board_id      --> setBoard_id(컬럼값)
//    title         --> setTitle(컬럼값)
//    contents      --> setContents(컬럼값)
//    created_date  --> setCreated_date(컬럼값)
//    view_count    --> setView_count(컬럼값)
// => 컬럼 이름과 일치하는 프로퍼티(setter)가 없다면 
// 그 컬럼의 값은 객체에 담을 수 없다.
// => 이 예제에서 컬럼 이름과 일치하는 프로퍼티는 title 밖에 없다.
// 
  public static void main(String[] args) throws Exception {
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(//
        Resources.getResourceAsStream(//
            "com/eomcs/mybatis/ex01/mybatis-config.xml"));

    SqlSession sqlSession = factory.openSession();

    List<Board> list = sqlSession.selectList("BoardMapper.selectBoard2");

    for (Board board : list) {
      System.out.printf("%d, %s, %s, %s, %d\n", board.getNo(), board.getTitle(), board.getContent(),
          board.getRegisteredDate(), board.getViewCount());
    }
    sqlSession.close();
  }
}

// 컬럼 이름과 자바 객체의 프로퍼티 이름을 같게 하기
// ---------------------------------------------------------------------
// <select id="selectBoard" resultType="com.eomcs.mybatis.ex01.Board">
// select
//   board_id as no,
//   title,
//   contents as content,
//   created_date as registeredDate,
//   view_count as viewCount
// from x_board
// </select>
// ---------------------------------------------------------------------
// => 컬럼의 값을 자바 객체에 담으려면 컬럼과 같은 이름의 프로퍼티가 있어야 한다.
// => 없다면 위와 같이 프로퍼티 명을 컬럼의 별명으로 지정하라.
//
// mybatis 설정 파일에서 fully-qualified class name 을 사용하는 대신에
// 짧은 이름으로 대체할 수 있다.
// <typeAliases>
// <typeAlias type="com.eomcs.mybatis.ex01.Board" alias="abc"/>
// </typeAliases>
//
// 그러면 이 별명을 어디에 사용하는가?
// => SQL 맵퍼 파일에서 클래스를 지정할 때 사용한다.
// <select id="selectBoard2" resultType="abc">
// select
// board_id as no,
// title,
// contents as content,
// created_date registeredDate,
// view_count viewCount
// from x_board
// </select>
//
// 참고
//
public class Exam0210 {

  public static void main(String[] args) throws Exception {
    InputStream inputStream = Resources.getResourceAsStream( //
        "com/eomcs/mybatis/ex01/mybatis-config02.xml");
    SqlSessionFactory factory = //
        new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = factory.openSession();

    List<Board> list = sqlSession.selectList("BoardMapper.selectBoard");

    for (Board board : list) {
      System.out.printf("%d, %s, %s, %s, %d\n", //
          board.getNo(), //
          board.getTitle(), //
          board.getContent(), //
          board.getRegisteredDate(), //
          board.getViewCount());
    }
    sqlSession.close();
  }
}
  <!-- mybatis 설정 파일을 작성할 ,
       자식 태그의 순서를 지켜야 한다.
       => mybatis 설정 파일 작성 규칙에 순서를 지키도록 정의되어 있다. 
   -->
  <properties resource="com/eomcs/mybatis/ex01/jdbc.properties"></properties>

  <!--  이름의 클래스명을 사용하는 대신에 짧은 이름의 별명을 사용해보자! -->
  <typeAliases>
    <!-- 주의!
      패키지를 포함한 클래스 이름은 항상 . 으로 표기해야 한다.
      /  파일 경로를 가리킬  사용한다. 
     -->
    <typeAlias type="com.eomcs.mybatis.ex01.Board" alias="Board"/>
  </typeAliases>

컬럼과 프로퍼티

  • SQL문은 태그 안에 작성한다.

  • select 태그 id : SQL문을 찾을 때 사용할 식별자이다. resultType : select 결과를 저장할 클래스이름이나 별명이다. 클래스이름을 경우 반드시 fully-qualified class name(패키지명을 포함한 클래스명)을 사용하라!

  • 값을 자바 객체에 넣는 규칙: => 컬럼명과 일치하는 셋터를 호출한다. 컬럼명 ==> set컬럼명() => 예) bno ==> setBno(값) 즉, Board board = new Board(); board.setBno(rs.getNo(“bno”)); 만약 컬럼 이름에 해당하는 셋터를 못 찾으면 호출하지 않는다.

  • 거울처럼 클래스 안에 있는 메서드를 알려주는 것들을 리플렉션 API라고 한다.

  • xml 문법 // &lessthan = < 를 의미한다. // 태그 안에 주석을 달면 안된다.

    select board_id, title, contents, created_date, view_count from x_board where board_id < #{ohora} </select>

    // xml 파서에게 전부 문자라고 알려준다. // 이게 없으면 파서는 < 를 태그 시작점이라고 생각한다.

페이징 처리

  • 오라클 https://m.blog.naver.com/wideeyed/221796538283
  • mysql https://ggmouse.tistory.com/198

sql 파라미터 지정하기

  • ${} 는 sql 삽입 공격을 당할 수 있기 때문에 사용하지 않는다.
  • 입력이 아니라 선택받는 것으로 한다면 활용할 수 있다.

dynamic sql - 조건문

if 조건문

  • 조건에 따라 생성할 SQL문을 제어할 수 있다.
    • 문법 : SQL문
    • 예 :
    • 여기서 no 는 파라미터 타입이 프리머티브 타입인 경우 마음대로 적을 수 있다.
    • 하지만 그 외의 타입은 정확하게 이름을 적어야 한다.
  • ”%” + keyword + “%” : keyword 가 포함된 것 전부 검색
  • ”%” + keyword : keyword 가 앞에 붙어있는 것 검색

where 절 사용

  • where 태그를 사용하면 or/and 앞에 아무것도 없을 때 or/and 를 자동으로 제거한다.

    or board_id = #{no} or title like concat('%', #{title}, '%') or contents like concat('%', #{content}, '%')

    </select>

    board_id = #{no} or title like concat('%', #{title}, '%') or contents like concat('%', #{content}, '%')

    </select>

trim 사용

  • or/and 자동 제거

    board_id = #{no} or title like concat('%', #{title}, '%') or contents like concat('%', #{content}, '%')

    </select>

Categories:

Updated: