Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[JDBC] 예제 소스 정리 - Mybatis 본문

네이버클라우드 AIaaS 개발자 양성과정 1기/DBMS, SQL, JDBC, Servlet

[JDBC] 예제 소스 정리 - Mybatis

끈기JK 2023. 2. 16. 08:35

com.eomcs.mybatis

 

예제 소스 정리

 

 

package com.eomcs.mybatis.ex01

 

 

Data Persistence Framework 도입 - 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) Mybatis 라이브러리 파일을 프로젝트에 등록하기
 - mvnrepository.com 또는 search.maven.org에서 mybatis를 검색하여 라이브러리 정보 알아낸다.
 - build.gradle 파일에 의존 라이브러리 정보를 추가한다.
 - 'gradle eclipse' 실행하여 라이브러리를 다운로드 받고, 이클립스 설정 파일에 등록한다.
 - 이클립스 프로젝트를 리프래시하여 변경된 설정 파일의 정보를 반영한다.
2) Mybatis 설정 파일 준비
 - mybatis.org 사이트에서 문서 페이지를 참조한다.
 - Mybatis 설정 파일(예: mybatis-config.xml)을 생성한다.
 - 문서 페이지를 참조하여 설정 파일의 내용을 변경한다.

package com.eomcs.mybatis.ex01.a;

import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0110 {

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

}

 

ex01/a/mybatis-config.xml

<?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>

  <!-- DBMS에 대한 정보를 설정한다.
       default 속성 : SQL을 실행할 때 연결할 DBMS 연결 정보의 ID
  -->
  <environments default="development">
  
    <!-- DBMS의 연결 정보는 다음과 같이 environment 태그에 설정한다. -->
    <!-- 예) 개발용 DBMS -->   
    <environment id="development">
      
      <!-- 트랜잭션 관리 방식을 지정한다. -->
      <transactionManager type="JDBC"/>
      
      <!-- DB 커넥션 풀에 관련된 정보와 DB 연결 정보를 설정한다.-->
      <dataSource type="POOLED">
        <property name="driver" value="org.mariadb.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://localhost:3306/studydb"/>
        <property name="username" value="study"/>
        <property name="password" value="1111"/>
      </dataSource>
    </environment>
    
    <!-- 예) 테스트용 DBMS  -->   
    <environment id="test">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="org.mybatis.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://localhost:3306/studydb"/>
        <property name="username" value="study"/>
        <property name="password" value="1111"/>
      </dataSource>
    </environment>
    
    <!-- 예) 실무에서 운용할 때 사용할 DBMS  -->   
    <environment id="operation">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="org.mybatis.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://localhost:3306/studydb"/>
        <property name="username" value="study"/>
        <property name="password" value="1111"/>
      </dataSource>
    </environment>
  </environments>
</configuration>

 

 

Data Persistence Framework 도입 - 좀 더 쉽게 Mybatis 설정 파일의 InputStream 얻는 방법
package com.eomcs.mybatis.ex01.a;

import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0120 {

  public static void main(String[] args) throws Exception {

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

    // => 이런 문제를 해결하기 위해 Mybatis는 도우미 객체를 제공한다.
    // => Resources 클래스의 메서드를 이용하면
    //    자바 클래스가 있는 패키지 폴더의 mybatis 설정 파일을 바로 지정할 수 있다.
    //
    InputStream mybatisConfigInputStream = Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex01/a/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();
  }

}

 

 

Data Persistence Framework 도입 - 코드 정리!
package com.eomcs.mybatis.ex01.a;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0130 {

  public static void main(String[] args) throws Exception {

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex01/a/mybatis-config.xml")).openSession();

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

    sqlSession.close();
  }

}

 

 

Mybatis 설정 파일 - DBMS 연결 정보를 .properties 파일로 분리하기
package com.eomcs.mybatis.ex01.b;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0110 {

  public static void main(String[] args) throws Exception {

    // 1) jdbc.properties 파일을 추가한다.
    //    => 이 파일에 DB 접속 정보를 저장한다.
    // 2) mybatis-config.xml 파일을 변경한다.
    //    => DB 접속 정보를 설정할 때 jdbc.properties 파일의 데이터를 사용한다.
    //
    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex01/b/mybatis-config.xml")).openSession();

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

    sqlSession.close();
  }

}

 

ex01/b/jdbc.properties

# jdbc.properties
driver=org.mariadb.jdbc.Driver
url=jdbc:mariadb://localhost:3306/studydb
username=study
password=1111

 

 

Mybatis 설정 파일 - SQL 매퍼 파일 설정과 SQL 문 사용법
package com.eomcs.mybatis.ex01.c;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0110 {

  public static void main(String[] args) throws Exception {


    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex01/c/mybatis-config.xml")).openSession();

    // 1) SQL 매퍼 파일 준비
    //  - mybatis.org 사이트에서 문서 페이지를 참조한다.
    //  - SQL이 들어 있는 파일(예: BoardMapper.xml)을 생성한다.
    //  - 문서 페이지를 참조하여 매퍼 파일의 내용을 변경한다.
    // 2) select 결과를 저장할 클래스 정의
    //  - Board 클래스 생성
    // 3) BoardMapper.xml 파일에 보관된 select 문 실행하기
    //  - SQL을 실행하고 결과 데이터를 객체에 담아 리턴한다.
    //  - mybatis 문서 페이지를 참조한다.
    //  - SqlSession.selectList("네임스페이스명.SQL아이디")
    //
    List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard");

    System.out.println(boards.size());

    sqlSession.close();
  }

}

 

ex01/c/BoardMapper.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">

<!-- SQL Mapper 파일:
=> SQL 문을 보관하는 파일이다.
=> SQL 문 종류에 따라 다른 태그를 사용한다.
    <select>SELECT 문</select>
    <insert>INSERT 문</insert>
    <update>UPDATE 문</update>
    <delete>DELETE 문</delete>
=> namespace 속성:  
   - SQL문이 소속된 그룹. 자바의 패키지명과 같은 역할을 한다.
   - 보통 그룹명은 SQL 맵퍼 파일이름으로 지정한다.
   - 다른 매퍼 파일과 구분하기 위해 파일의 경로명을 포함하기도 한다.
   - 실무에서는 주로 SQL을 사용할 인터페이스나 클래스 경로를 그룹명으로 지정한다.
   - 물론 어떤 이름으로 지정해도 상관없지만, 가능한 위의 규칙을 준수하는 것이 유지보수에 좋다.-->
<mapper namespace="BoardMapper">

  <!-- select 태그:
       => select 문을 보관할 때 사용한다.
       => id 속성: 
          SQL문을 찾을 때 사용할 식별자.
       => resultType 속성: 
          select 결과(한 개의 레코드 값)를 담을 객체의 타입이다. 
          클래스명은 반드시 패키지 이름을 포함(fully-qualified name=FQName=QName)해야 한다.                 
   -->
  <select id="selectBoard" resultType="com.eomcs.mybatis.ex01.c.Board">
    select 
      board_id,
      title,
      contents,
      created_date,
      view_count
    from x_board
    order by board_id desc
  </select>
</mapper>

 

ex01/c/Board.java

package com.eomcs.mybatis.ex01.c;

import java.io.Serializable;
import java.sql.Date;

public class Board implements Serializable {
  private static final long serialVersionUID = 1L;

  int no;
  String title;
  String content;
  Date registeredDate;
  int viewCount;

  @Override
  public String toString() {
    return "Board [no=" + no + ", title=" + title + ", content=" + content + ", registeredDate="
        + registeredDate + ", viewCount=" + viewCount + "]";
  }

  public int getNo() {
    return no;
  }

  public void setNo(int no) {
    this.no = no;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getContent() {
    return content;
  }

  public void setContent(String content) {
    this.content = content;
  }

  public Date getRegisteredDate() {
    return registeredDate;
  }

  public void setRegisteredDate(Date registeredDate) {
    this.registeredDate = registeredDate;
  }

  public int getViewCount() {
    return viewCount;
  }

  public void setViewCount(int viewCount) {
    this.viewCount = viewCount;
  }

}

 

 

Mybatis 설정 파일 - 도메인 클래스의 별명을 설정하는 방법과 사용법
package com.eomcs.mybatis.ex01.d;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0110 {

  public static void main(String[] args) throws Exception {

    // 도메인 클래스의 별명을 부여하기
    // - SQL 매퍼 파일에서 데이터를 리턴하거나 파라미터로 데이터를 받을 때
    //   클래스의 전체 이름(패키지 이름을 포함)을 지정해야 한다.
    // - 패키지 이름이 길 경우 사용하기가 번거롭다.
    // - mybatis 설정 파일에서 fully-qualified class name 을 사용하는 대신에
    //   짧은 이름으로 대체할 수 있다.
    //
    // 1) mybatis-config.xml 변경
    //    - 다음과 같이 클래스 전체 이름에 대해 별명을 지정한다.
    // 
    // <typeAliases>
    //   <typeAlias type="com.eomcs.mybatis.ex01.d.Board" alias="board"/>
    // </typeAliases>
    //
    // 2) BoardMapper.xml 변경
    //    - 결과를 담을 클래스를 지정할 때 클래스 전체 이름을 사용하는 대신에 
    //      mybatis 설정 파일에 등록된 별명을 사용할 수 있다.
    //    - 다음과 같이 SQL 맵퍼 파일에서 클래스를 지정할 때 별명을 사용한다.
    // 
    // <select id="selectBoard" resultType="board">
    //   select
    //       board_id as no,
    //       title,
    //       contents as content,
    //       created_date registeredDate,
    //       view_count viewCount
    //   from x_board
    // </select>
    //
    // 참고!
    // => 자바 primitive type과 wrapper 클래스, String 클래스,
    //    일부 유틸리티 클래스 등에 대해서는 mybatis가 미리 별명을 지정하였다.
    // => 예)
    //     int       ->  _int
    //     float     ->  _float
    //     java.lang.Integer     -> int
    //     java.lang.Float       -> float
    //     java.lang.String      -> string
    //     java.util.Map         -> map
    //     java.util.HashMap     -> hashMap
    //
    //
    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex01/d/mybatis-config.xml")).openSession();

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

    System.out.println(boards.size());

    sqlSession.close();
  }

}

 

ex01/d/mybatis-config.xml

<?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>

  <properties resource="com/eomcs/mybatis/ex01/d/jdbc.properties"></properties>

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

  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  
  <mappers>
    <mapper resource="com/eomcs/mybatis/ex01/d/BoardMapper.xml"/>
  </mappers>
</configuration>

 

ex01/d/BoardMapper.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="BoardMapper">
  
  <!-- 자바 클래스를 지정할 때 mybatis 설정 파일에 별명이 등록되어 있다면,
       그 별명을 사용할 수 있다.
       참고!
       별명은 대소문자를 구분하지 않는다. -->
  <select id="selectBoard" resultType="board">
    select 
      board_id,
      title,
      contents,
      created_date,
      view_count
    from x_board
  </select>
</mapper>

 

Mybatis 설정 파일 - 도메인 클래스의 별명을 설정하는 또 다른 방법
package com.eomcs.mybatis.ex01.e;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    // 패키지에 소속된 전체 클래스에 대해 별명을 자동으로 부여할 수 있다.
    // => 단 별명은 클래스 이름이다.
    //
    // <typeAliases>
    //   <package name="com.eomcs.mybatis.ex01.e"/>
    // </typeAliases>
    //
    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex01/e/mybatis-config.xml")).openSession();

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

    System.out.println(boards.size());

    sqlSession.close();
  }

}

 

ex01/e/BoardMapper.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="BoardMapper">
  
  <!-- 자동으로 등록된 클래스의 별명은 클래스 이름과 같다. 
       별명은 대소문자를 구분하지 않지만 
       가능한 클래스 이름을 그대로 사용한다. -->
  <select id="selectBoard" resultType="board">
    select 
      board_id,
      title,
      contents,
      created_date,
      view_count
    from x_board
  </select>
</mapper>

 

ex01/e/mybatis-config.xml

<?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>

  <properties resource="com/eomcs/mybatis/ex01/e/jdbc.properties"></properties>

  <typeAliases>
    <!-- 패키지에 소속된 모든 클래스에 대해 별명을 자동으로 부여할 수 있다.
         클래스 이름이 별명으로 설정된다.-->
    <package name="com.eomcs.mybatis.ex01.e"/>
  </typeAliases>

  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  
  <mappers>
    <mapper resource="com/eomcs/mybatis/ex01/e/BoardMapper.xml"/>
  </mappers>
</configuration>

 

 

com.eomcs.mybatis.ex02

 

 

ex02/a/BoardMapper.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="BoardMapper">
  
    <!-- SQL문은 태그 안에 작성한다.
       <select> 태그에는 select 문장을, 
       <insert> 태그에는 insert 문장을,
       <update> 태그에는 update 문장을,
       <delete> 태그에는 delete 문장을 작성한다.
       그런데 insert/update/delete 인 경우 
       <insert>/<update>/<delete> 구분없이 태그를 사용해도 된다.
       그 이유는 SQL문을 찾을 때 id 속성 값으로 찾기 때문이다.
       그럼에도 불구하고 유지보수의 일관성을 위해 
       SQL 문의 따라 적절한 태그를 사용하라!
   -->
  <select id="selectBoard" resultType="Board">
    select 
      board_id,
      title,
      contents,
      created_date,
      view_count
    from x_board
  </select>
</mapper>

 

 

SqlSession 사용법 - SQL 문을 실행하는 메서드
package com.eomcs.mybatis.ex02.a;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex02/a/mybatis-config.xml")).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> boards = sqlSession.selectList("BoardMapper.selectBoard");

    System.out.println(boards.size());

    sqlSession.close();
  }

}

 

 

ex02/b/BoardMapper.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="BoardMapper">
  
  <!-- select 태그
       id : SQL문을 찾을 때 사용할 식별자이다.
       resultType : select 결과를 저장할 클래스이름이나 별명이다. 
       클래스 이름은 반드시 fully-qualified class name(패키지명을 포함한 클래스명)을 사용하라! 
  -->
  <select id="selectBoard" resultType="Board">
    select 
      board_id, <!-- Board.setBoard_id() 호출 -->
      title,    <!-- Board.setTitle() 호출 -->
      contents, <!-- Board.setContents() 호출 -->
      created_date, <!-- Board.setCreated_date() 호출 -->
      view_count    <!-- Board.setView_count() 호출 -->
    from x_board
  </select>
  <!-- 
       값을 자바 객체에 넣는 규칙:
       => 컬럼명과 일치하는 셋터를 호출한다.
          컬럼명 ==> set컬럼명()
       => 예) 
          bno ==> setBno(값)
          즉, 
          Board board = new Board();
          board.setBno(rs.getNo("bno"));
          만약 컬럼 이름에 해당하는 셋터를 못 찾으면 호출하지 않는다.
   -->
   
  <!-- 위의 SQL문을 mybatis는 내부에서  
       다음과 같은 코드로 실행할 것이다.
       
       ArrayList<Board> list = new ArrayList<>();
       
       while (rs.next()) {
           Board board = new Board();
           board.setBoard_id(rs.getNo("board_id")); // 이런 셋터가 없다.
           board.setTitle(rs.getString("title")); // 이 셋터는 있다.
           board.setContents(rs.getString("contents")); // 이런 셋터가 없다.
           board.setCreated_date(rs.getDate("created_date")); // 이런 셋터가 없다.
           board.setView_count(rs.getDate("view_count")); // 이런 셋터가 없다.
           list.add(board);
       } 
       return list;
       
       그러나 안타깝게도 Board 클래스에는 컬럼 이름과 일치하는 셋터가 
       딱 한개만 있다. title 컬럼이다.
       그 외 컬럼 값은 셋터가 없기 때문에 저장할 수 없다.
       해결책?
       => 셋터의 이름(프로퍼티 이름)과 같은 이름으로 컬럼의 별명을 설정하라! 
  -->
</mapper>

 

 

SqlSession.selectList() 사용법 - select 문 실행하기
package com.eomcs.mybatis.ex02.b;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

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

    // selectList()
    // => 여러 개의 결과 값을 리턴하는 select를 실행할 때 사용한다.
    // => select 실행으로 생성된 각 row의 값은 resultType에 지정한 클래스의 인스턴스에 저장된다.
    // => 그리고 그 인스턴스는 List 구현체에 담겨 리턴된다.
    // => 결과가 없으면 size 가 0인 List 객체를 리턴한다.
    //

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

    for (Board b : boards) {
      System.out.println(b);
      //      System.out.printf("%d,%s,%s,%s,%d\n",
      //          b.getNo(),
      //          b.getTitle(),
      //          b.getContent(),
      //          b.getRegisteredDate(),
      //          b.getViewCount());
    }
    // 실행 결과가 기대와 같지 않은 이유?
    // => mybatis에서 결과 값을 Board 객체에 담을 때 일부 컬럼의 값을 담지 못했기 때문이다.
    //
    // 왜 일부 컬럼의 값을 Board에 담지 못했는가?
    // => mybatis에서 결과의 컬럼 값을 자바 객체에 담을 때
    //    컬럼 이름과 같은 이름을 가진 프로퍼티(셋터 메서드)를 찾는다.
    // => 컬럼 이름과 일치하는 프로퍼티가 없다면,
    //    컬럼 이름과 일치하는 필드를 찾는다.
    // => 컬럼 이름과 일치하는 세터나 필드가 없다면 
    //    해당 컬럼의 값이 자바 객체에 저장되지 못한다.
    // => 컬럼과 일치하는 프로퍼티나 필드가 한 개도 없다면,
    //    자바 객체를 만들지 않고 null을 리턴한다.

    sqlSession.close();
  }

}

Mybatis에서 select 결과를 자바 인스턴스에 담을 때 규칙 
=> 컬럼 이름과 같은 프로퍼티를 찾아서 값을 담는다.
=> 자바에서 '프로퍼티'란?
   세터/게터를 가리키는 용어다.
   예) setNo()/getNo()
=> 프로퍼티 이름?
   세터/게터 이름에서 set/get 이름을 제거한 후, 나머지 이름이다.
   단 첫 알파벳은 소문자이다.
   예) setNo()/getNo() => no
   예) setCreatedDate()/getCreatedDate() => createdDate
=> 주의! 
   필드 이름이 프로퍼티 이름이 아니다!

결론!
- Board 클래스의 프로퍼티 이름을 보면 
  no, title, content, registeredDate, viewCount 가 있다.
- Board 클래스의 필드 이름을 보면
  no, title, content, registeredDate, viewCount 가 있다.
- 이 프로퍼티나 필드 중에서 컬럼 이름과 일치하는 프로퍼티나 필드는 title 뿐이다.
- Mybatis는 컬럼 이름과 같은 이름을 가진 
  프로퍼티(title,contents) 또는 필드에 대해서만 결과 값을 넣어 준다.
- 그래서 Board 객체를 출력해보면 title 값만 정상적으로 출력된다.

해결책?
=> 컬럼 이름을 프로퍼티명이나 필드명과 같게 하라.
   - DB의 이름짓는 규칙과 자바의 이름 짓는 규칙은 다르다.
   - 또한 DBMS 마다 이름 짓는 규칙이 다르다.
   - 그래서 자바에서 프로퍼티 이름을 지을 때는 특정 DBMS에 종속되게 지어서는 안된다.
   - 자바는 자바의 명명 규칙을 따르고, DB는 DBMS의 명명 규칙을 따르면 된다.
=> 그러면 어떻게 하자는 것인가?
   - select 할 때 컬럼의 별명을 자바 프로퍼티(또는 필드) 이름과 같게 하라!

 

 

ex02/c/BoardMapper.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="BoardMapper">
  
  <!-- 
       컬럼명을 자바 객체의 프로퍼티명(셋터명)과 일치시키기:
       컬럼의 이름이 프로퍼티(또는 필드) 이름과 다르다면,
       객체에 값을 넣을 수 없다.
       컬럼 이름을 프로퍼티(또는 필드) 이름과 일치시켜야만 정확하게 값을 객체에 담을 수 있다.
       select 문에서 컬럼의 별명을 프로퍼티명(또는 필드명)과 같게 하라! 
  --> 
  <select id="selectBoard" resultType="Board">
    select 
      board_id as no, <!-- Board.setNo() 호출 -->
      title,    <!-- Board.setTitle() 호출 -->
      contents as content, <!-- Board.setContent() 호출 -->
      created_date as registeredDate, <!-- Board.setRegisteredDate() 호출 -->
      view_count as viewCount    <!-- Board.setViewCount() 호출 -->
    from x_board
  </select>
</mapper>

 

 

SqlSession.selectList() 사용법 - 컬럼 별명을 이용하여 자바 객체의 프로퍼티 이름과 일치시키기
package com.eomcs.mybatis.ex02.c;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

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

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

    // select 문에서 컬럼을 지정할 때 자바 인스턴스의 프로퍼티 이름과 다르다면 
    // 별명을 이용하여 프로퍼티명과 같게 한다.
    // 컬러몀과 자바 객체의 프로퍼티명이 일치한다면 다음과 같이 정상적으로 데이터를 꺼내올 수 있다.
    for (Board b : boards) {
      System.out.printf("%d,%s,%s,%s,%d\n",
          b.getNo(),
          b.getTitle(),
          b.getContent(),
          b.getRegisteredDate(),
          b.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>
//---------------------------------------------------------------------
//=> 컬럼의 값을 자바 객체에 담으려면 컬럼과 같은 이름의 프로퍼티가 있어야 한다.
//=> 없다면 위와 같이 프로퍼티 명을 컬럼의 별명으로 지정하라.

 

 

ex02/d/BoardMapper.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="BoardMapper">
  
  <!-- 컬럼명과 자바 객체의 프로퍼티 명을 미리 연결한다.
       type: 자바 객체의 클래스명 또는 별명
       id: 연결 정보를 가리키는 식별자. SQL 문을 설정할 때 사용한다. 
  -->
  <resultMap type="Board" id="BoardMap">
    <!-- 컬럼명과 자바 객체의 프로퍼티명을 연결한다.
         column="테이블 컬럼명"
         property="자바 객체의 프로퍼티명"
         시작태그와 끝태그 사이에 추가 내용이 없다면 끝태그를 생략하고
         대신에 시작태그의 끝에 /를 붙인다.
   
         PK 컬럼을 지정할 때는 id 엘리먼트를 사용하고, 
         일반 컬럼을 지정할 때는 result 엘리먼트를 사용하라! -->
         
    <id column="board_id" property="no"/> 
    <!-- 의미 => board_id 컬럼 값은 Board.setNo()을 호출해서 넣으라는 의미 -->
    
    <!-- 컬럼 이름과 자바 객체의 프로퍼티 이름이 같을 경우 생략해도 된다. -->
    <!--  
    <result column="title" property="title"/>
    -->
    
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- 위에서 정의한 연결 정보를 사용하고 싶다면,
       resultMap="컬럼과 프로퍼티의 연결을 정의한 resultMap 아이디" 를 설정하라! 
       참고!
       resultType="클래스명 또는 별명"
  -->
  <select id="selectBoard" resultMap="BoardMap">
    select 
      board_id, <!-- BoardMap의 연결정보를 참조하기 때문에 별명을 주지 않아도 된다. -->
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
  </select>
</mapper>

 

 

SqlSession.selectList() 사용법 - <resultMap>을 통해 자바 객체의 프로퍼티 이름과 일치시키기
package com.eomcs.mybatis.ex02.d;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

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

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

    // select 문에서 컬럼 값을 자바 인스턴스의 프로퍼티와 맞추기 위해 
    // 별명을 부여하는 방식은 번거롭다.
    // 특히 컬럼 개수가 많은 경우 더더욱 번거롭다.
    // 이를 해결하기 위해 mybatis는 컬럼의 이름과 프로퍼티 이름을 연결해주는 문법을 제공한다.
    //    <resultMap></resultMap>
    // 
    for (Board b : boards) {
      System.out.printf("%d,%s,%s,%s,%d\n",
          b.getNo(),
          b.getTitle(),
          b.getContent(),
          b.getRegisteredDate(),
          b.getViewCount());
    }

    sqlSession.close();
  }

}

 

 

ex02/e/BoardMapper.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="BoardMapper">
  
  <!-- select 결과를 Map 객체에 받을 수 있다. 
       - 각각의 레코드 값은 각각의 Map 객체에 보관된다.
       - 그리고 List에 Map 객체 목록이 보관된다.
  -->
  <select id="selectBoard" resultType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
  </select>
</mapper>

 

 

SqlSession.selectList() 사용법 - 결과 레코드를 Map 객체로 받기
package com.eomcs.mybatis.ex02.e;

import java.util.List;
import java.util.Map;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0110 {

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

    // 결과 타입이 Map 이면,
    // - selectList()의 리턴 타입은 List<Map> 이 된다.
    // 
    List<Map<String,Object>> list = sqlSession.selectList("BoardMapper.selectBoard");

    // 각각의 Map 객체에는 레코드 값이 보관되어 있다.
    // - 즉 레코드의 각 컬럼 값이 Map 객체에 보관되어 있다.
    // - 컬럼 값을 꺼낼 때는 select 할 때 사용한 컬럼이름으로 꺼내야 한다.
    // 
    for (Map<String,Object> map : list) {
      System.out.printf("%d,%s,%s,%s,%d\n",
          map.get("board_id"),
          map.get("title"),
          map.get("contents"),
          map.get("created_date"),
          map.get("view_count"));
    }

    sqlSession.close();
  }

}

 

 

ex02/f/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- select 문의 실행 결과가 1개 인 경우 -->
  <select id="selectBoard1" resultMap="BoardMap">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where board_id=1
  </select>
  
  
  <!-- select 문의 실행 결과가 없을 경우 -->
  <select id="selectBoard2" resultMap="BoardMap">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where board_id=100
  </select>
  
  <!-- 결과를 Map 객체로 리턴 받을 수 있다. -->
  <select id="selectBoard3" resultType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where board_id=1
  </select>
  
  <!-- select 문의 실행 결과가 2개 이상일 때는 selectOne() 으로 실행할 수 없다. -->
  <select id="selectBoard4" resultMap="BoardMap">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
  </select>
</mapper>

 

 

SqlSession.selectOne() 사용법 - 한 개의 결과를 조회할 때 사용
package com.eomcs.mybatis.ex02.f;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

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

    // selectOne()
    // - select 결과가 0 또는 1개 일 때 호출할 수 있다.
    // 
    Board b = sqlSession.selectOne("BoardMapper.selectBoard1");

    System.out.printf("%d,%s,%s,%s,%d\n",
        b.getNo(),
        b.getTitle(),
        b.getContent(),
        b.getRegisteredDate(),
        b.getViewCount());

    sqlSession.close();
  }

}

 

 

SqlSession.selectOne() 사용법 - 결과가 0 개 일 때
package com.eomcs.mybatis.ex02.f;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

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

    // selectOne()
    // - select 결과가 0 또는 1개 일 때 호출할 수 있다.
    // - 결과가 없으면 리턴 값은 null 이다. 
    // 
    Board b = sqlSession.selectOne("BoardMapper.selectBoard2");

    if (b == null) {
      System.out.println("해당 번호의 게시글이 없습니다.");
      return;
    }

    System.out.printf("%d,%s,%s,%s,%d\n",
        b.getNo(),
        b.getTitle(),
        b.getContent(),
        b.getRegisteredDate(),
        b.getViewCount());

    sqlSession.close();
  }

}

 

 

SqlSession.selectOne() 사용법 - 결과 값을 Map 객체로 받기
package com.eomcs.mybatis.ex02.f;

import java.util.Map;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0210 {

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

    // Map 객체로 받으려면 SQL 매퍼에서 다음과 같이 resultType을 설정해야 한다.
    //    <select id="selectBoard3" resultType="map" parameterType="int">
    //      select 
    //        board_id,
    //        title,    
    //        contents,
    //        created_date, 
    //        view_count  
    //      from x_board
    //      where board_id=#{no}
    //    </select>
    // 
    // - 컬럼 이름(이나 별명)으로 컬럼 값을 저장하기 때문에 
    //   map 객체에 컬럼 값을 꺼낼 때 컬럼 이름(이나 별명)을 사용해야 한다.
    // 
    Map<String,Object> map = sqlSession.selectOne("BoardMapper.selectBoard3");

    if (map == null) {
      System.out.println("해당 번호의 게시글이 없습니다.");
      return;
    }

    System.out.printf("%d,%s,%s,%s,%d\n",
        map.get("board_id"),
        map.get("title"),
        map.get("contents"),
        map.get("created_date"),
        map.get("view_count"));

    sqlSession.close();
  }

}

 

 

SqlSession.selectOne() 사용법 - 한 개를 초과한 개수의 결과를 조회할 때
package com.eomcs.mybatis.ex02.f;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0310 {

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

    // selectOne()
    // - 여러 개의 결과가 나오는 select 문에 대해 호출하면 예외가 발생한다.
    // 
    Board b = sqlSession.selectOne("BoardMapper.selectBoard4");

    System.out.printf("%d,%s,%s,%s,%d\n",
        b.getNo(),
        b.getTitle(),
        b.getContent(),
        b.getRegisteredDate(),
        b.getViewCount());

    sqlSession.close();
  }

}

 

 

com.eomcs.mybatis.ex03

 

 

ex03/a/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- SQL 문에 값 삽입하기 : in-parameter 지정하기
       => parameterType에 지정된 객체의 프로퍼티 명을 사용하여 값을 삽입한다.
          예) #{프로퍼티명}
       => paramterType이 primitive/String/wrapper class 인 경우 아무 이름을 적어도 된다.
          예) #{아무이름}
       => parameterType이 Map 객체인 경우는 Map에 저장된 값의 key를 적는다.
          예) #{key} 
       => parameterType에 지정할 수 있는 타입:
       int      => _int
       Integer  => int
       String   => string
       Map      => map
       HashMap  => hashmap
       Board    => board
       ...
   -->
  <!-- selectOne(sqlid, int) --> 
  <select id="select1" resultMap="BoardMap" parameterType="int">
    select 
      board_id, 
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where board_id=#{hoho}
  </select>
  
  <!-- selectList(sqlid, string) --> 
  <select id="select2" resultMap="BoardMap" parameterType="string">
    select 
      board_id, 
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where title=#{okok}
  </select>
  
  <!-- selectList(sqlid, int) --> 
  <select id="select3" resultMap="BoardMap" parameterType="int">
    select 
      board_id, 
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where board_id &lt; #{hul}
  </select>
  
  <!-- selectList(sqlid, int) --> 
  <select id="select4" resultMap="BoardMap" parameterType="int">
  <![CDATA[
    select 
      board_id, 
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where board_id < #{no}
  ]]>
  </select>
  
</mapper>

 

 

SQL 문에 삽입할 파라미터 전달하기 - 한 개의 int 값 넘기기
package com.eomcs.mybatis.ex03.a;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

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

    // in-parameter에 int 값 넘기기
    // => SQL을 실행할 때 파라미터 값을 전달하려면
    //   두 번째 파라미터로 전달해야 한다.
    //      예) selectOne(sqlID, in-parameter 값)
    // => in-parameter 값의 타입은 Object이다.
    //    자바 원시 타입의 값을 지정하면 자동으로 오토 박싱되어 mybatis에 전달된다.
    // => 여러 개의 값을 전달해야 한다면,
    //    도메인 객체나 Map 객체에 담아 전달하라!

    // 예) 특정 번호의 게시글을 가져온다.
    Board board = sqlSession.selectOne("BoardMapper.select1", 5); // auto-boxing 수행

    if (board != null) {
      System.out.printf("%d,%s,%s,%s,%d\n",
          board.getNo(),
          board.getTitle(),
          board.getContent(),
          board.getRegisteredDate(),
          board.getViewCount());
    }
    sqlSession.close();
    System.out.println("실행 완료!");
  }

}

 

 

SQL 문에 삽입할 파라미터 전달하기 - 한 개의 String 값 넘기기
package com.eomcs.mybatis.ex03.a;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

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

    // 예) 특정 제목의 게시글을 가져온다.
    List<Board> boards = sqlSession.selectList("BoardMapper.select2", "제목2");

    for (Board b : boards) {
      System.out.printf("%d,%s,%s,%s,%d\n",
          b.getNo(),
          b.getTitle(),
          b.getContent(),
          b.getRegisteredDate(),
          b.getViewCount());
    }
    sqlSession.close();
    System.out.println("실행 완료!");
  }

}

 

 

SQL 문에 삽입할 파라미터 전달하기 - XML Entity를 사용할 때
package com.eomcs.mybatis.ex03.a;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0130 {

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

    // XML 파서가 혼동을 일으킬 수 있는(XML 파싱 오류 발생) 문자를 사용할 때, 
    // 그 문자 대신 XML Entity를 사용하라.
    //   " => &quot;
    //   ' => &apos;
    //   & => &amp;
    //   < => &lt;
    //   > => &gt;
    // 
    // 예) 특정 번호 미만의 게시글을 가져온다.
    List<Board> boards = sqlSession.selectList("BoardMapper.select3", 3);

    for (Board b : boards) {
      System.out.printf("%d,%s,%s,%s,%d\n",
          b.getNo(),
          b.getTitle(),
          b.getContent(),
          b.getRegisteredDate(),
          b.getViewCount());
    }
    sqlSession.close();
    System.out.println("실행 완료!");
  }

}

 

 

SQL 문에 삽입할 파라미터 전달하기 - CDATA 섹션을 사용할 때 : <[!CDATA[ SQL 문 []]>
package com.eomcs.mybatis.ex03.a;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0140 {

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

    // CDATA 섹션
    // - XML 파서(parser)에게 해당 블록의 내용물이 단순 텍스트임을 알려주는 명령이다.
    // - 문법
    //      <![CDATA[ 내용물 ]]>
    // - 내용물 안에 XML 파서가 혼동을 일으킬 문자가 많을 때 사용하기 적합하다.
    // 
    // 예) 특정 번호 미만의 게시글을 가져온다.
    List<Board> boards = sqlSession.selectList("BoardMapper.select4", 3);

    for (Board b : boards) {
      System.out.printf("%d,%s,%s,%s,%d\n",
          b.getNo(),
          b.getTitle(),
          b.getContent(),
          b.getRegisteredDate(),
          b.getViewCount());
    }
    sqlSession.close();
    System.out.println("실행 완료!");
  }

}

 

 

ex03/b/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- selectList(sqlid, Map) 
    => Map에서 값을 꺼낼 때는 값을 저장할 때 사용한 key를 이용한다.
    => #{key}
  -->
  <select id="select1" resultMap="BoardMap" parameterType="map">
  <![CDATA[
    select 
      board_id, 
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where board_id >= #{startNo} and board_id <= #{endNo}
  ]]>
  </select>

  <!-- 일반 객체를 파라미터로 받을 수 있다.
       parameterType="클래스명 또는 별명"
       일반 객체에서 값을 꺼내려면 프로퍼티(getter)명을 지정해야 한다.
       예) 
          #{title} ==> getTitle()의 리턴 값을 의미한다.
          #{content} ==> getContent()의 리턴 값을 의미한다.
        -->
  <!-- insert(sqlId, Board) -->
  <insert id="insert" parameterType="board">
    insert into x_board(title,contents,created_date)
    values(#{title}, #{content}, now())
  </insert>
  
</mapper>

 

 

SQL 문에 삽입할 파라미터 전달하기 - Map을 이용하여 여러 개의 값 넘기기
package com.eomcs.mybatis.ex03.b;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

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

    // selectList(),selectOne(),insert(),update(),delete()
    // - selectList(SQL ID)
    // - selectList(SQL ID, 파라미터)
    // - 위와 같이 SQL을 실행할 때 오직 한 개의 파라미터만 넘길 수 있다.
    // - 여러 개의 파라미터를 넘기고 싶다면 객체에 담아서 넘겨라!
    // 
    // 예) 특정 범위의 번호에 해당하는 게시글을 가져온다.
    //
    Map<String,Object> params = new HashMap<>();
    params.put("startNo", 2);
    params.put("endNo", 4);

    List<Board> boards = sqlSession.selectList("BoardMapper.select1", params);

    for (Board b : boards) {
      System.out.printf("%d,%s,%s,%s,%d\n",
          b.getNo(),
          b.getTitle(),
          b.getContent(),
          b.getRegisteredDate(),
          b.getViewCount());
    }
    sqlSession.close();
    System.out.println("실행 완료!");
  }

}

 

 

SQL 문에 삽입할 파라미터 전달하기 - 일반 객체를 이용하여 여러 개의 값 넘기기
package com.eomcs.mybatis.ex03.b;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

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

    // Board 객체에 값을 저장하여 전달하기
    // - 단 값을 꺼낼 수 있도록 겟터(프로퍼티)가 있어야 한다.
    // 
    Board board = new Board();
    board.setTitle("제목입니다");
    board.setContent("내용입니다.");

    // insert 문을 실행할 때는 insert() 메서드를 호출한다.
    // - 리턴 값은 executeUpdate()의 실행 결과이다.
    // - 즉 insert 된 데이터의 개수이다.
    //
    // 예) 게시글을 입력한다.
    //
    int count = sqlSession.insert("BoardMapper.insert", board);
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    // 현재 SqlSession 객체가 수동 commit 상태이기 때문에
    // 데이터 변경을 수행한 후 commit을 반드시 실행해야 한다.
    // 
    sqlSession.commit();

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

ex03/c/BoardMapper.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="BoardMapper">
  
  <!-- insert(sqlId, Board) -->
  <insert id="insert1" parameterType="board">
    insert into x_board(title,contents,created_date)
    values(#{title}, #{content}, now())
  </insert>
  
  <!-- insert(sqlId, Map) -->
  <insert id="insert2" parameterType="map">
    insert into x_board(title,contents,created_date)
    values(#{title}, #{content}, now())
  </insert>
  
  <!-- insert(sqlId, Board) -->
  <insert id="insert3" parameterType="board" 
          useGeneratedKeys="true" keyColumn="board_id" keyProperty="no">
    insert into x_board(title,contents,created_date)
    values(#{title}, #{content}, now())
  </insert>
  
  <!-- update(sqlId, Board) -->
  <update id="update" parameterType="board">
    update x_board set
      title=#{title},
      contents=#{content}
    where
      board_id=#{no}
  </update>
  
  <!-- delete(sqlId, no) -->
  <delete id="delete" parameterType="int">
    delete from x_board 
    where 
      board_id=#{no}
  </delete>
</mapper>

 

 

insert 문 실행 - Board 객체에 값을 담아 파라미터로 넘기기
package com.eomcs.mybatis.ex03.c;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

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

    Board board = new Board();
    board.setTitle("제목입니다111"); // #{title} 을 사용하여 SQL 문에 값을 삽입한다.
    board.setContent("내용입니다111."); // #{content} 를 사용하여 SQL 문에 값을 삽입한다.

    // insert 문을 실행할 때는 insert() 메서드를 호출한다.
    // - 리턴 값은 executeUpdate()의 실행 결과이다.
    // - 즉 insert 된 데이터의 개수이다.
    // - update(), delete()을 사용해도 결과는 같다.
    //
    // 예) 게시글을 입력한다.
    //
    int count = sqlSession.insert("BoardMapper.insert1", board);
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    // SqlSessionFactory의 openSession()을 통해 SqlSession 얻을 때는 
    // autocommit이 기본으로 false이다.
    // autocommit?
    // - insert/update/delete 과 같이 데이터를 변경하는 작업은
    //   위험하기 때문에 DBMS의 임시 메모리에 그 작업 결과를 보관한다.
    // - 클라이언트에서 최종적으로 변경 사항에 대해 확정해줘야만 진짜 테이블에 값을 반영한다.
    //
    // 현재 SqlSession 객체가 수동 commit 상태이기 때문에
    // 데이터 변경을 수행한 후 commit을 반드시 실행해야 한다.
    // 
    sqlSession.commit();
    // commit 명령을 내리지 않으면 insert/update/delete을 통해 수행한 데이터 변경 작업을 
    // 실제 테이블에 반영하지 않는다.
    // close() 할 때 자동으로 취소된다.
    //
    // 용어 정리!
    // commit() : 임시 메모리에 저장된 작업 결과를 실제 테이블에 반영시키는 명령
    // rollback() : 임시 메모리에 저장된 작업 결과를 취소하는 명령
    //
    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

insert 문 실행 - Map 객체에 값을 담아 파라미터로 넘기기
package com.eomcs.mybatis.ex03.c;

import java.util.HashMap;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0120 {

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

    HashMap<String,Object> params = new HashMap<>();
    params.put("title", "제목입니다222"); // #{title} 을 사용하여 SQL 문에 값을 삽입한다.
    params.put("content", "내용입니다222."); // #{content} 를 사용하여 SQL 문에 값을 삽입한다.

    // 예) 게시글을 입력한다.
    //
    int count = sqlSession.insert("BoardMapper.insert2", params);
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    sqlSession.commit();

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

update 문 실행
package com.eomcs.mybatis.ex03.c;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0210 {

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

    Board board = new Board();
    board.setNo(1); // #{no} 
    board.setTitle("제목 변경!!!"); // #{title}
    board.setContent("내용 변경!!!"); // #{content}

    // update 문을 실행할 때는 update() 메서드를 호출한다.
    // - 리턴 값은 executeUpdate()의 실행 결과이다.
    // - 즉 update 된 데이터의 개수이다.
    //
    // 예) 게시글을 변경한다.
    //
    int count = sqlSession.update("BoardMapper.update", board);
    System.out.printf("%d 개의 데이터를 변경 했음!\n", count);

    sqlSession.commit();

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

delete 문 실행
package com.eomcs.mybatis.ex03.c;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0310 {

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

    // delete 문을 실행할 때는 delete() 메서드를 호출한다.
    // - 리턴 값은 executeUpdate()의 실행 결과이다.
    // - 즉 delete 된 데이터의 개수이다.
    //
    // 예) 게시글을 삭제한다.
    //
    int count = sqlSession.delete("BoardMapper.delete", 10);
    System.out.printf("%d 개의 데이터를 삭제 했음!\n", count);

    sqlSession.commit();

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

insert 문 실행 - INSERT 실행 후 자동 증가된 PK값 가져오기
package com.eomcs.mybatis.ex03.c;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0410 {

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

    Board board = new Board();
    board.setTitle("제목입니다333");
    board.setContent("내용입니다333.");

    System.out.printf("insert 실행 전: %s\n", board);

    // insert 문을 실행한 후에 자동 증가한 PK 값을 알아내기
    // - 자동 증가한 PK 값은 SQL을 실행할 때 넘겨준 객체에 담겨있을 것이다.
    // - 단 SQL 매퍼 파일에서 insert 문을 정의할 때 설정해 줘야 한다.
    //    <insert id="insert3" parameterType="board" 
    //        useGeneratedKeys="true" 
    //        keyColumn="board_id" 
    //        keyProperty="no">
    //      insert into x_board(title,contents,created_date)
    //      values(#{title}, #{content}, now())
    //    </insert>
    // 
    // - useGeneratedKeys 속성: 자동 증가한 PK 컬럼 값을 사용할 것인지 지정한다.
    // - keyColumn 속성 : 자동 증가 pk 컬럼의 이름을 지정한다.
    // - keyProperty 속성 : 자동 증가 pk 컬럼의 값을 저장할 자바 객체의 프로퍼티를 지정한다.
    // 
    // 예) 게시글을 입력한다.
    //
    int count = sqlSession.insert("BoardMapper.insert3", board);
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    sqlSession.commit();

    sqlSession.close();

    System.out.printf("insert 실행 후: %s\n", board);

    System.out.println("실행 완료!");
  }

}

 

 

ex03/d/BoardMapper.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="BoardMapper">
  
  <!-- insert(sqlId, Board) -->
  <insert id="insert" parameterType="board">
    insert into x_board(title,contents,created_date)
    values(#{title}, #{content}, now())
  </insert>
  
</mapper>

 

 

트랜잭션 다루기 - openSession(true) : 자동 커밋 SqlSession 객체 얻기
package com.eomcs.mybatis.ex03.d;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {

    // openSession(auto commit 여부)
    // - true : 데이터 변경 후 즉시 커밋한다.
    // - false : 데이터 변경 후 commit()을 호출할 때까지 실제 테이블에 변경 사항을 반영하지 않는다.
    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex03/d/mybatis-config.xml")).openSession(true);

    Board board = new Board();
    board.setTitle("제목입니다xxx");
    board.setContent("내용입니다xxx.");

    int count = sqlSession.insert("BoardMapper.insert", board);
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    // commit() 을 호출하지 않아도 즉시 테이블에 변경 사항을 반영한다.

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

트랜잭션 다루기 - openSession() : 수동 커밋
package com.eomcs.mybatis.ex03.d;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {

    // openSession(auto commit 여부)
    // - true : 데이터 변경 후 즉시 커밋한다.
    // - false : 데이터 변경 후 commit()을 호출할 때까지 실제 테이블에 변경 사항을 반영하지 않는다.
    // 
    // openSession()
    // - 기본이 수동 커밋이다.
    // - openSession(false) 와 같다.
    // 
    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex03/d/mybatis-config.xml")).openSession();

    Board board = new Board();
    board.setTitle("제목입니다yyy");
    board.setContent("내용입니다yyy");

    int count = sqlSession.insert("BoardMapper.insert", board);
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    // commit() 을 호출하지 않으면 테이블에 변경 사항을 반영하지 않는다.

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

트랜잭션 다루기 - commit() : 데이터 변경 결과를 실제 테이블에 반영하기
package com.eomcs.mybatis.ex03.d;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0130 {

  public static void main(String[] args) throws Exception {

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex03/d/mybatis-config.xml")).openSession();

    Board board = new Board();
    board.setTitle("제목입니다zzz");
    board.setContent("내용입니다zzz");

    int count = sqlSession.insert("BoardMapper.insert", board);
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    // 수동 커밋 상태일 때는 
    // - 데이터 변경 후 commit() 을 명시적으로 호출해야 한다.
    // - 그래야 실제 테이블에 변경 사항이 반영된다.
    sqlSession.commit();

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

ex03/e/BoardMapper.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="BoardMapper">
  
  <!-- 부모 테이블 데이터 입력 : 게시글 입력 -->
  <insert id="insertBoard" parameterType="board"
          useGeneratedKeys="true" keyColumn="board_id" keyProperty="no">
    insert into x_board(title,contents,created_date)
    values(#{title}, #{content}, now())
  </insert>
  
  <!-- 자식 테이블 데이터 입력 : 첨부파일 입력 -->
  <insert id="insertFile" parameterType="map">
    insert into x_board_file(file_path, board_id)
    values(#{filePath},#{boardNo})
  </insert>
  
</mapper>

 

 

트랜잭션 다루기 - 수동 커밋의 필요성
package com.eomcs.mybatis.ex03.e;

import java.util.HashMap;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex03/e/mybatis-config.xml")).openSession(true);

    // 1) 게시글 입력
    Board board = new Board();
    board.setTitle("게시글1");
    board.setContent("내용1");

    int count = sqlSession.insert("BoardMapper.insertBoard", board);
    System.out.printf("%d 개의 게시글을 입력 했음!\n", count);

    HashMap<String,Object> fileInfo = new HashMap<>();

    // 2) 첫 번째 첨부파일 입력
    fileInfo.put("filePath", "aaa.gif");
    fileInfo.put("boardNo", board.getNo());
    count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
    System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);

    // 3) 두 번째 첨부파일 입력
    fileInfo.put("filePath", "bbb.gif");
    fileInfo.put("boardNo", board.getNo());
    count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
    System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);

    // 4) 세 번째 첨부파일 입력
    fileInfo.put("filePath", 
        "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + ".gif");
    fileInfo.put("boardNo", board.getNo());
    count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
    System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);

    // auto commit 일 때,
    // - 데이터 변경 SQL 문을 실행하면 즉시 테이블에 적용한다.
    // - 따라서 세 번째 첨부파일을 입력하다가 오류가 발생하더라도 
    //   이전에 수행했던 데이터 변경 작업은 완료된 상태다.
    // 

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

트랜잭션 다루기 - 수동 커밋의 활용
package com.eomcs.mybatis.ex03.e;

import java.util.HashMap;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {

    // 수동 커밋 상태로 동작하는 SqlSession 객체를 얻는다.
    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex03/e/mybatis-config.xml")).openSession();

    // 1) 게시글 입력
    Board board = new Board();
    board.setTitle("게시글2");
    board.setContent("내용2");

    int count = sqlSession.insert("BoardMapper.insertBoard", board);
    System.out.printf("%d 개의 게시글을 입력 했음!\n", count);

    HashMap<String,Object> fileInfo = new HashMap<>();

    // 2) 첫 번째 첨부파일 입력
    fileInfo.put("filePath", "aaa.gif");
    fileInfo.put("boardNo", board.getNo());
    count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
    System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);

    // 3) 두 번째 첨부파일 입력
    fileInfo.put("filePath", "bbb.gif");
    fileInfo.put("boardNo", board.getNo());
    count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
    System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);

    // 4) 세 번째 첨부파일 입력
    fileInfo.put("filePath", 
        "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + "12345678901234567890123456789012345678901234567890"
            + ".gif");
    fileInfo.put("boardNo", board.getNo());
    count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
    System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);

    // 수동 commit 일 때,
    // - 작업을 완료한 후 반드시 commit()을 호출해야만 실제 테이블에 변경사항을 적용한다.
    // - commit() 을 호출하지 않고 SqlSession 객체를 close() 하면 자동 rollback 이다.
    // - SqlSession 객체를 재사용하는 방식이면,
    //   오류가 발생했을 때 개발자가 명시적으로 rollback()을 호출해 줘야 한다.
    // 
    sqlSession.commit();

    sqlSession.close();

    System.out.println("실행 완료!");
  }

}

 

 

ex03/f/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- #{} 을 사용하여 값이 아닌 SQL 코드를 삽입할 수 있는가?
       => 없다! 오류 발생!!!
     
    [#{} 문법의 한계] 
    in-parameter 는 컬럼의 값을 지정할 때 사용한다. 
    그리고 in-parameter 자리에 값을 놓을 때는 #{프로퍼티명} 문법을 사용한다.
      
      select *
      from x_board
      where title = #{value}
      
    그러나 테이블 이름이나 컬럼 이름, 
    SQL 키워드(예: select, from, insert, values, into, set, asc, desc, order, by 등)가 들어갈 자리는 
    in-parameter로 지정할 수 없다. 
    in-parameter로 지정할 수 없는 자리에 #{프로퍼티명}을 사용할 수 없다.
    
      select *
      from #{name} <==== 안된다!
      where title = #{value}
      order by 
        #{column} #{sort}  <==== 둘 다 안된다.
        
  --> 
  <select id="select1" resultMap="BoardMap" parameterType="string">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    order by board_id #{sortType}
  </select>
  

  <!-- 문자열 치환 문법(${})으로 SQL 코드를 삽입하기
       => SQL 키워드(테이블 이름과 컬럼 이름 포함)가 들어갈 자리에 
          in-parameter 처럼 값을 넣고 싶다면 ${프로퍼티명} 을 사용하라! 
       [경고!]
       => 사용자가 입력한 값을 직접 SQL 코드에 삽입하는 경우 "SQL 삽입 공격"을 받을 수 있다.
       => 따라서 ${프로퍼티명} 문법을 사용할 때는 절대로 사용자가 입력한 값을 그대로 전달하지 말라!
       => 사용자가 입력한 값을 자바 코드에서 판단하여 자바 코드로 입력한 값을 전달하라!
     -->
  <select id="select2" resultMap="BoardMap" parameterType="string">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    order by board_id ${sortType}
  </select>
  
  <!-- 
     ${} 는 SQL 코드를 삽입할 수 있다.
   -->
  <select id="select3" resultMap="BoardMap" parameterType="string">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    order by ${sort}
  </select>
  
  <!-- 
     ${} 는 SQL 코드를 삽입할 수 있다.
   -->
  <select id="select4" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    order by ${columnName} ${sortType}
  </select>
  
  <!-- 
     ${} 는 SQL 코드를 삽입할 수 있다.
   -->
  <select id="count" resultType="int" parameterType="string">
    select 
      count(*)  
    from ${tableName}
  </select>
  
  <delete id="delete1" parameterType="string">
    delete from x_board
    where title = #{value}
  </delete>
  
  <delete id="delete2" parameterType="string">
    delete from x_board
    where ${condition}
  </delete>
</mapper>

 

 

#{} 문법의 한계
package com.eomcs.mybatis.ex03.f;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

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

    // 정렬 방식을 파라미터로 넘기기
    // => #{} 문법은 오직 값만 삽입할 수 있다.
    // => SQL 코드를 삽입할 수 없다.
    // => 파라미터 값을 SQL에 그대로 삽입하려면
    //    문자열 치환 문법인 ${} 를 사용해야 한다.
    List<Board> boards = sqlSession.selectList("BoardMapper.select1", "desc");

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

    sqlSession.close();
  }

}

 

 

${} 문법 : 문자열 치환(string substitution) 문법의 활용
package com.eomcs.mybatis.ex03.f;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

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

    // 문자열 치환(string substitution) 문법(${})을 사용하면 SQL 코드를 파라미터로 넘길 수 있다. 
    //
    List<Board> boards = sqlSession.selectList("BoardMapper.select2", "desc");

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

    sqlSession.close();
  }

}

 

 

${} 문법 : 문자열 치환(string substitution) 문법의 활용 II
package com.eomcs.mybatis.ex03.f;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0130 {

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

    // 정렬 방식을 파라미터로 넘기기
    // => ${} 문법은 파라미터 값을 SQL 문에 그대로 삽입한다.
    //
    List<Board> boards = sqlSession.selectList("BoardMapper.select3", 
        "created_date desc, title asc");

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

    sqlSession.close();
  }

}

 

 

${} 문법 : 문자열 치환(string substitution) 문법의 활용 IV
package com.eomcs.mybatis.ex03.f;

import java.util.HashMap;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0140 {

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

    // 컬럼 이름과 정렬 타입을 파라미터로 넘기기
    //
    HashMap<String,Object> params = new HashMap<>();
    params.put("columnName", "title");
    params.put("sortType", "asc");

    List<Board> boards = sqlSession.selectList("BoardMapper.select4", params);

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

    sqlSession.close();
  }

}

 

 

${} 문법 : 문자열 치환(string substitution) 문법의 활용 III
package com.eomcs.mybatis.ex03.f;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0150 {

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

    // 테이블명을 파라미터로 넘기기
    // => ${} 문법은 파라미터 값을 SQL 문에 그대로 삽입한다.
    //
    int count = sqlSession.selectOne("BoardMapper.count", "x_board");

    System.out.println(count);

    sqlSession.close();

 

 

${} 문법의 위험성 - #{} 사용할 때
package com.eomcs.mybatis.ex03.f;

import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0210 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);
    System.out.print("삭제할 게시글의 제목? ");
    String input = keyboard.nextLine();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession(true);

    // #{} 문법은 SQL에 값을 삽입할 때 사용한다.
    // 사용자가 입력한 값(문자열)에 sql 코드를 포함하더라도 
    // 그냥 값으로 취급하기 때문에 실행에는 영향을 끼치지 않는다.
    // 즉 'SQL 삽입 공격'이 불가능하다.
    // 삭제할 게시글의 제목에 SQL에 영향을 끼치는 코드를 삽입하여 실행해 보라!
    // => 어떤 영향도 주지 못할 것이다.
    int count = sqlSession.delete("BoardMapper.delete1", input);

    System.out.println(count);

    sqlSession.close();
    keyboard.close();
  }

}

 

 

${} 문법의 위험성 - ${} 사용할 때
package com.eomcs.mybatis.ex03.f;

import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Exam0220 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색 항목:\n  1. 제목\n  2. 내용\n  3. 번호\n검색할 항목은? ");
    int menuNo = Integer.parseInt(keyboard.nextLine());

    String condition = null;
    switch (menuNo) {
      case 1:
        System.out.print("삭제할 게시글의 제목? ");
        condition = "title='" + keyboard.nextLine() + "'";
        break;
      case 2:
        System.out.print("삭제할 게시글의 내용? ");
        condition = "contents='" + keyboard.nextLine() + "'";
        break;
      case 3:
        System.out.print("삭제할 게시글의 번호? ");
        condition = "board_id=" + keyboard.nextLine();
        break;
      default:
        System.out.println("메뉴 번호가 옳지 않습니다.");
        keyboard.close();
        return;
    }

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession(true);

    // ${} 문법은 SQL에 코드를 사입할 때 사용한다.
    // 잘 쓰면 매우 편리하다.
    // => SQL 문을 한 개만 만들어 놓고 
    //    조건 변경하면서 다양한 방식으로 사용할 수 있다.
    // => 즉 게시글 제목, 내용, 번호를 조건으로 삭제할 수 있는 SQL 문을 쉽게 만들 수 있다.
    // 
    // 문제는 잘못된 방식으로 사용하면 위험하다.
    // => 사용자의 입력 값을 정제하지 않고 그대로 SQL문에 삽입하면 
    //    해킹이 가능한 상태가 될 수 있어 매우 위험하다.
    //
    // 제목을 입력할 때 다음과 같이 입력해 보라!
    // => a' or 't'='t
    // => 사용자가 위와 같이 입력했다고 가정하면 
    //    실행할 SQL 문은 다음과 같다.
    //       delete from x_board
    //       where title='a' or 't'='t'
    //    즉 x_board 테이블의 모든 데이터를 삭제하는 SQL 문이 만들어진다.
    //
    int count = sqlSession.delete("BoardMapper.delete2", condition);

    System.out.println(count);

    sqlSession.close();
    keyboard.close();
  }

}

 결론!
 - ${} 문법을 사용하지 말라는 것이 아니다.
 - ${} 문법을 사용했을 때 여러 개의 SQL 문을 만들 필요가 없어 매우 편리해지는 경우가 있다.
   즉 약간의 조건에 따라 SQL 문이 바뀌는 상황에서 ${} 문법은 매우 유용하다.
 - 다만 SQL 삽입 공격이 불가능하도록 주의해서 사용해야 한다.
   즉 사용자가 입력한 값이 SQL에 영향을 끼치지 않도록 해야 한다.

 

 

com.eomcs.mybatis.ex04.a

 

 

ex04/a/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- 제목으로 게시글 검색하기 -->
  <select id="select1" resultMap="BoardMap" parameterType="string">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where title like concat('%', #{value}, '%')
    order by board_id desc
  </select>
  
  <!-- 내용으로 게시글 검색하기 -->
  <select id="select2" resultMap="BoardMap" parameterType="string">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where contents like concat('%', #{value}, '%')
    order by board_id desc
  </select>
  
  <!-- 여러 SQL 문에 공통으로 포함되는 코드가 있다면 다음과 같이 
       별도의 sql 태그에 작성해 두고 사용하면 편리하다. -->
  <sql id="sql1">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
  </sql>
  
  <sql id="sql2">
    order by board_id desc
  </sql>
  
    <!-- 제목으로 게시글 검색하기 -->
  <select id="select3" resultMap="BoardMap" parameterType="string">
    <include refid="sql1"/>
    where title like concat('%', #{value}, '%')
    <include refid="sql2"/>
  </select>
  
  <!-- 내용으로 게시글 검색하기 -->
  <select id="select4" resultMap="BoardMap" parameterType="string">
    <include refid="sql1"/>
    where contents like concat('%', #{value}, '%')
    <include refid="sql2"/>
  </select>
</mapper>

 

 

<sql> 태그 사용법 (사용 전)
package com.eomcs.mybatis.ex04.a;

import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색 항목:\n  1. 제목\n  2. 내용\n검색 항목? ");
    int menuNo = Integer.parseInt(keyboard.nextLine());

    if (!(menuNo == 1 || menuNo == 2)) {
      System.out.println("검색 항목 번호가 옳지 않습니다.");
      keyboard.close();
      return;
    }

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/a/mybatis-config.xml")).openSession();

    List<Board> boards = null;

    if (menuNo == 1) {
      boards = sqlSession.selectList("BoardMapper.select1", keyword);
    } else if (menuNo == 2) {
      boards = sqlSession.selectList("BoardMapper.select2", keyword);
    }

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

    sqlSession.close();
  }

}

 

 

<sql> 태그 사용법 (사용 후)
package com.eomcs.mybatis.ex04.a;

import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색 항목:\n  1. 제목\n  2. 내용\n검색 항목? ");
    int menuNo = Integer.parseInt(keyboard.nextLine());

    if (!(menuNo == 1 || menuNo == 2)) {
      System.out.println("검색 항목 번호가 옳지 않습니다.");
      keyboard.close();
      return;
    }

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/a/mybatis-config.xml")).openSession();

    List<Board> boards = null;

    // 여러 SQL문에 공통들어 가는 코드가 있다면 
    // <sql> 태그를 사용하여 별도로 정의할 수 있다.
    // <include> 태그를 사용하여 <sql> 태그의 값을 가져올 수 있다.
    // 
    if (menuNo == 1) {
      boards = sqlSession.selectList("BoardMapper.select3", keyword);
    } else if (menuNo == 2) {
      boards = sqlSession.selectList("BoardMapper.select4", keyword);
    }

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

    sqlSession.close();
  }

}

 

 

ex04/b/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- 제목으로 게시글 검색하기 -->
  <select id="select1" resultMap="BoardMap" parameterType="string">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where title like concat('%', #{value}, '%')
    order by board_id desc
  </select>
  
  <!-- 내용으로 게시글 검색하기 -->
  <select id="select2" resultMap="BoardMap" parameterType="string">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where contents like concat('%', #{value}, '%')
    order by board_id desc
  </select>
  
  <!-- if 태그를 사용하면 값의 유무에 따라 SQL 문을 제어할 수 있다. -->
  <!-- 문법: 
       => <if test="조건">
       => 조건은 true/false를 리턴하는 계산식이어야 한다.
       => 파라미터 타입이 자바 원시 타입, String, 래퍼 클래스의 경우
          값을 꺼낼 때 프로퍼티 이름은 #{아무이름} 을 쓰면 된다.
  -->
  <select id="select3" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where 
      <if test="menuNo == 1">
        title like concat('%', #{keyword}, '%')
      </if>
      <if test="menuNo == 2">
        contents like concat('%', #{keyword}, '%')
      </if>
    order by board_id desc
  </select>
  
  <!-- 조건이 여러 개일 경우 if 태그 보다 choose 태그가 더 편리하다.
       자바의 switch 문과 사용법이 비슷하다. -->
  <select id="select4" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where 
    <choose>
      <when test="menuNo == 1">
        title like concat('%', #{keyword}, '%')
      </when>
      <when test="menuNo == 2">
        contents like concat('%', #{keyword}, '%')
      </when>
      <otherwise>
        1!=1
      </otherwise>
    </choose>
    order by board_id desc
  </select>
</mapper>

 

 

Dynamic SQL - if 태그 사용법(사용 전)
package com.eomcs.mybatis.ex04.b;

import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색 항목:\n  1. 제목\n  2. 내용\n검색 항목? ");
    int menuNo = Integer.parseInt(keyboard.nextLine());

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/b/mybatis-config.xml")).openSession();

    List<Board> boards = null;

    // dynamic sql?
    // => 조건에 따라 SQL이 변경되는 것.
    // => mybatis는 이를 위해 조건문, 반복문 등을 다룰 수 있도록 특별한 태그를 제공한다.
    //
    // dynamic sql 사용 전:
    // - 검색 항목 선택에 따라 SQL 문이 달라지기 때문에 
    //   다음과 같이 where 절의 일부분만 다른,
    //   SQL문을 여러 개 작성해야 한다.
    // - 그리고 조건에 따라 실행할 SQL 문을 구분해서 호출해야 한다.
    // 
    if (menuNo == 1) {
      boards = sqlSession.selectList("BoardMapper.select1", keyword);
    } else if (menuNo == 2) {
      boards = sqlSession.selectList("BoardMapper.select2", keyword);
    }

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

    sqlSession.close();
  }

}

 

 

Dynamic SQL - if 태그 사용법(사용 후)
package com.eomcs.mybatis.ex04.b;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색 항목:\n  1. 제목\n  2. 내용\n검색 항목? ");
    int menuNo = Integer.parseInt(keyboard.nextLine());

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/b/mybatis-config.xml")).openSession();

    // dynamic sql 사용 후:
    // - if 태그를 사용하여 조건에 따라 다른 SQL 문을 만들 수 있다.
    // - 이렇게 SQL 문이 고정되는 것이 아니라 변경될 수 있는 것을 
    //   'Dynamic SQL' 이라고 한다.
    // 
    HashMap<String,Object> params = new HashMap<>();
    params.put("menuNo", menuNo);
    params.put("keyword", keyword);

    // Dynamic SQL 을 사용하면 여러 개의 SQL 문을 만들 필요가 없다.
    List<Board> boards = sqlSession.selectList("BoardMapper.select3", params);

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

    sqlSession.close();
  }

}

 

 

Dynamic SQL - choose/when/otherwise 태그 사용법
package com.eomcs.mybatis.ex04.b;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam210 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색 항목:\n  1. 제목\n  2. 내용\n검색 항목? ");
    int menuNo = Integer.parseInt(keyboard.nextLine());

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/b/mybatis-config.xml")).openSession();

    // 조건이 여러 개일 때는 if 태그 보다 choose 태그를 사용하는 것이 
    // SQL을 다루기 더 편하다.
    // 
    HashMap<String,Object> params = new HashMap<>();
    params.put("menuNo", menuNo);
    params.put("keyword", keyword);

    // Dynamic SQL 을 사용하면 여러 개의 SQL 문을 만들 필요가 없다.
    List<Board> boards = sqlSession.selectList("BoardMapper.select4", params);

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

    sqlSession.close();
  }

}

 

 

ex04/c/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- 다음 SQL 문의 문제점은 
       조건에 일치하는 경우가 없을 때 
       where 다음에 놓이는 조건문이 없다는 것이다.
       그래서 실행할 때 SQL문법 오류가 발생한다. -->
  <select id="select0110" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where 
      <if test="menuNo == 1">
        title like concat('%', #{keyword}, '%')
      </if>
      <if test="menuNo == 2">
        contents like concat('%', #{keyword}, '%')
      </if>
    order by board_id desc
  </select>

  
  <select id="select0120" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    <where> 
      <if test="menuNo == 1">
        title like concat('%', #{keyword}, '%')
      </if>
      <if test="menuNo == 2">
        contents like concat('%', #{keyword}, '%')
      </if>
    </where>
    order by board_id desc
  </select>
  
  <!-- where 절에 여러 개의 조건이 삽입될 때 문제점 -->
  <select id="select0210" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where 
      <if test="title != null">
        title like concat('%', #{title}, '%')
      </if>
      <if test="contents != null">
        and contents like concat('%', #{contents}, '%')
      </if>
    order by board_id desc
  </select>
  
  <!-- where 태그를 사용하면,
       1) 조건이 한 개도 없을 경우,  where 절을 추가하지 않는다.
       2) 조건 앞뒤에 and, or 연산자가 있을 경우, 자동으로 제거한다. 
  -->
  <select id="select0220" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    <where> 
      <if test="title != null">
        title like concat('%', #{title}, '%')
      </if>
      <if test="contents != null">
        and contents like concat('%', #{contents}, '%')
      </if>
    </where>
    order by board_id desc
  </select>
  
  <!-- <where> 태그 대신에 <trim> 태그를 사용하여 
       문장 앞뒤에 오는 OR 나 AND 를 제거할 수 있다. 
  -->
  <select id="select0230" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    <trim prefix="where" prefixOverrides="or|and">
      <if test="title != null">
        title like concat('%', #{title}, '%')
      </if>
      <if test="contents != null">
        and contents like concat('%', #{contents}, '%')
      </if>
    </trim>   
    order by board_id desc
  </select>  
  
  <!-- 특정 조건이 있을 경우에만 select를 수행할 때, 
       1) 조건이 없으면 결과를 리턴하지 않는 방법?
          다음과 같이 where 절에 기본 조건을 명시한다.
          where 
            1!=1  <== 기본 조건. 예) 무조건 거짓이 되게 하기
  -->
  <select id="select0310" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where
      1!=1
      <if test="title != null">
        or title like concat('%', #{title}, '%')
      </if>
      <if test="contents != null">
        or contents like concat('%', #{contents}, '%')
      </if>
    order by board_id desc
  </select>
</mapper>

 

 

Dynamic SQL - where 태그의 필요성
package com.eomcs.mybatis.ex04.c;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색 항목:\n  1. 제목\n  2. 내용\n검색 항목? ");
    int menuNo = Integer.parseInt(keyboard.nextLine());

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();

    // where 다음에 일치하는 조건이 없을 경우
    // SQL 문법 오류가 발생한다.
    // => 검색 항목의 번호를 1, 2가 아닌 다른 숫자를 입력한 후 테스트 해 보라!
    //
    HashMap<String,Object> params = new HashMap<>();
    params.put("menuNo", menuNo);
    params.put("keyword", keyword);

    List<Board> boards = sqlSession.selectList("BoardMapper.select0110", params);

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

    sqlSession.close();
  }

}

 

 

Dynamic SQL - where 태그 사용법
package com.eomcs.mybatis.ex04.c;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색 항목:\n  1. 제목\n  2. 내용\n검색 항목? ");
    int menuNo = Integer.parseInt(keyboard.nextLine());

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();

    // <where> 태그 안에 놓이는 SQL이 없을 경우
    // where 절은 삽입되지 않는다.
    //
    HashMap<String,Object> params = new HashMap<>();
    params.put("menuNo", menuNo);
    params.put("keyword", keyword);

    List<Board> boards = sqlSession.selectList("BoardMapper.select0120", params);

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

    sqlSession.close();
  }

}

 

 

Dynamic SQL - where 태그의 필요성 II
package com.eomcs.mybatis.ex04.c;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0210 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("제목?(건너 뛰기: 빈 문자열) ");
    String title = keyboard.nextLine();

    System.out.print("내용?(건너 뛰기: 빈 문자열) ");
    String contents = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();

    // where 절에 여러 개의 조건이 있을 경우 발생할 수 있는 문제점을 확인해 보자.
    // 테스트 1)
    //   - 제목, 내용 모두 검색어를 입력한다.
    //     => 해당 제목과 내용을 포함하고 있는 게시글을 정상적으로 리턴한다.
    // 테스트 2)
    //   - 제목만 입력한다.
    //     => where 다음에 title 컬럼의 조건을 검사하는 코드가 붙기 때문에 
    //        정상적으로 수행한다.
    // 테스트 3)
    //   - 제목, 내용 모두 빈 문자열로 입력한다.
    //     => where 다음에 조건을 지정하는 SQL 문이 없기 때문에 SQL 문법 오류가 발생한다.
    // 테스트 4)
    //   - 내용만 입력한다.
    //     => where 다음에 내용을 검사하는 코드가 붙는다.
    //        문제는 제목을 검사하는 조건이 빠지는 바람에 
    //        내용을 검사하는 코드 앞에 and 가 남아 있어서 SQL 문법 오류가 발생한다.
    ///         select board_id, title, contents, created_date, view_count
    //          from x_board
    //          where and contents like concat('%', ?, '%')
    //          order by board_id desc
    // 해결책)
    //   - <where> 태그를 사용하면 
    //     1. 조건이 비어 있을 때 where 절을 붙이기 않는다. 
    //     2. and, or 잔여물이 붙어 있을 때 자동으로 제거한다. 
    //   - <trim> 태그를 사용하면
    //     1. 제목이 빠진 후에 내용 조건을 검사하는 코드 앞에 and 가 붙는 것을 제거할 수 있다.
    //
    HashMap<String,Object> params = new HashMap<>();

    if (title.length() > 0) {
      params.put("title", title);
    }

    if (contents.length() > 0) {
      params.put("contents", contents);
    }

    List<Board> boards = sqlSession.selectList("BoardMapper.select0210", params);

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

    sqlSession.close();
  }

}

 

 

Dynamic SQL - where 태그 사용법 II
package com.eomcs.mybatis.ex04.c;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0220 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("제목?(건너 뛰기: 빈 문자열) ");
    String title = keyboard.nextLine();

    System.out.print("내용?(건너 뛰기: 빈 문자열) ");
    String contents = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();

    // <where> 태그를 사용하면 
    // 1) 조건이 비어 있을 때 where 절을 붙이기 않는다. 
    // 2) and, or 잔여물이 붙어 있을 때 자동으로 제거한다. 
    // 
    HashMap<String,Object> params = new HashMap<>();

    if (title.length() > 0) {
      params.put("title", title);
    }

    if (contents.length() > 0) {
      params.put("contents", contents);
    }

    List<Board> boards = sqlSession.selectList("BoardMapper.select0220", params);

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

    sqlSession.close();
  }

}

 

 

Dynamic SQL - trim 태그 사용법
package com.eomcs.mybatis.ex04.c;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0230 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("제목?(건너 뛰기: 빈 문자열) ");
    String title = keyboard.nextLine();

    System.out.print("내용?(건너 뛰기: 빈 문자열) ");
    String contents = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();

    // 내용만 입력 했을 때 문제점
    // => 다음과 같이 where 다음에 내용을 검사하는 코드가 붙는다.
    //    문제는 제목을 검사하는 조건이 빠지는 바람에 
    //    내용을 검사하는 코드 앞에 and 가 남아 있어서 SQL 문법 오류가 발생한다.
    ///         select board_id, title, contents, created_date, view_count
    //          from x_board
    //          where and contents like concat('%', ?, '%')
    //          order by board_id desc
    // 해결책)
    //   - <where> 태그를 사용하면 된다.
    //   - <trim> 태그를 사용하여 쓸데없이 붙은 and 나 or 를 제거하면 된다.
    // 
    HashMap<String,Object> params = new HashMap<>();

    if (title.length() > 0) {
      params.put("title", title);
    }

    if (contents.length() > 0) {
      params.put("contents", contents);
    }

    List<Board> boards = sqlSession.selectList("BoardMapper.select0230", params);

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

    sqlSession.close();
  }

}

 

 

Dynamic SQL - 무조건 false가 되는 조건을 포함해야 하는 경우
package com.eomcs.mybatis.ex04.c;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0310 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("제목?(건너 뛰기: 빈 문자열) ");
    String title = keyboard.nextLine();

    System.out.print("내용?(건너 뛰기: 빈 문자열) ");
    String contents = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();

    // 사례1)
    //    where 
    //      <if test="title != null">
    //        title like concat('%', #{title}, '%')
    //      </if>
    //      <if test="contents != null">
    //        or contents like concat('%', #{contents}, '%')
    //      </if>
    //
    // - 위 where 절의 경우 
    //   => 검색어로 제목을 입력하면 해당 검색어를 제목으로 포함하는 게시글을 결과에 포함한다.
    //   => 검색어로 내용을 입력하면 해당 검색어를 내용으로 포함하는 게시글을 결과에 포함한다.
    //   => 만약 둘 다 입력하지 않으면 where 절 문법 오류가 발생한다.
    // 
    // 요구사항
    // - 검색어를 모두 입력하지 않았을 때 SQL 오류를 발생시키지 않고 빈 결과를 리턴하게 하는 방법은?
    //   => where 절에 무조건 false를 리턴하는 조건을 추가하면 된다.
    // 
    HashMap<String,Object> params = new HashMap<>();

    if (title.length() > 0) {
      params.put("title", title);
    }

    if (contents.length() > 0) {
      params.put("contents", contents);
    }

    List<Board> boards = sqlSession.selectList("BoardMapper.select0310", params);

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

    sqlSession.close();
  }

}

 

ex04/d/BoardMapper.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="BoardMapper">
  
  <!-- udpate를 실행할 때 
       값을 변경하는 컬럼에 대해서만 update를 수행하게 할 수 있다. 
       <set>과 <if> 태그를 조합하면 된다.
  -->
  <update id="update1" parameterType="board">
    update x_board set
      <if test="title != null">
        title=#{title},
      </if>
      <if test="content != null">
        contents=#{content}
      </if>
    where board_id=#{no}
  </update>
  
  <!-- set 태그는 컬럼 값을 변경하는 문장 앞뒤에 쓸데없이 붙어 있는 콤마(,)를 제거해 준다. -->
  <update id="update2" parameterType="board">
    update x_board 
    <set>
      <if test="title != null">
        title=#{title},
      </if>
      <if test="content != null">
        contents=#{content}
      </if>
    </set>  
    where board_id=#{no}
  </update>
  
</mapper>

 

 

Dynamic SQL - update 문에 if 태그의 활용
package com.eomcs.mybatis.ex04.d;

import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    Board board = new Board();

    // 게시글 번호 입력 받기
    System.out.print("변경할 게시글의 번호? ");
    board.setNo(Integer.parseInt(keyboard.nextLine()));

    System.out.print("제목?(건너 뛰기: 빈 문자열) ");
    String input = keyboard.nextLine();
    if (input.length() > 0) {
      board.setTitle(input);
    }

    System.out.print("내용?(건너 뛰기: 빈 문자열) ");
    input = keyboard.nextLine();
    if (input.length() > 0) {
      board.setContent(input);
    }

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/d/mybatis-config.xml")).openSession(true);

    // if 태그를 활용하면 전체 컬럼이 아니라 일부 항목만 변경하는 SQL을 만들 수 있다.
    // 테스트 1)
    //   - 제목, 내용 모두 변경하기
    // 텍스트 2)
    //   - 내용만 변경하기
    // 테스트 3)
    //   - 제목만 변경하기
    //   - set 다음에 오는 문장 뒤에 콤마(,)가 붙기 때문에 SQL 문법 오류가 발생한다.
    //        update x_board set                 
    //               title=?,    <=== 문장 뒤에 콤마(,)가 붙어 있다.                     
    //        where board_id=?
    //   - 해결책?
    //     <set> 태그를 사용하라!
    // 
    int count = sqlSession.update("BoardMapper.update1", board);

    System.out.println(count);

    sqlSession.close();
  }

}

 

 

Dynamic SQL - set 태그의 필요성
package com.eomcs.mybatis.ex04.d;

import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    Board board = new Board();

    // 게시글 번호 입력 받기
    System.out.print("변경할 게시글의 번호? ");
    board.setNo(Integer.parseInt(keyboard.nextLine()));

    System.out.print("제목?(건너 뛰기: 빈 문자열) ");
    String input = keyboard.nextLine();
    if (input.length() > 0) {
      board.setTitle(input);
    }

    System.out.print("내용?(건너 뛰기: 빈 문자열) ");
    input = keyboard.nextLine();
    if (input.length() > 0) {
      board.setContent(input);
    }

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/d/mybatis-config.xml")).openSession(true);

    // 다음과 같이 set 문장 앞뒤에 쓸데없이 콤마(,)가 붙을 경우 자동으로 제거하는 방법?
    //        update x_board set                 
    //               title=?,    <=== 문장 뒤에 콤마(,)가 붙어 있다.                     
    //        where board_id=?
    // 
    // - <set> 태그를 사용하라!
    // 
    int count = sqlSession.update("BoardMapper.update2", board);

    System.out.println(count);

    sqlSession.close();
  }

}

 

ex04/e/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- foreach 를 사용하지 않으면 값의 개수 만큼 SQL 코드를 작성해야 한다. -->
  <select id="select1" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    <where> 1=0
      <if test="keyword1 != ''">
        or title like concat('%', #{keyword1}, '%')
      </if>
      <if test="keyword2 != ''">
        or title like concat('%', #{keyword2}, '%')
      </if>
      <if test="keyword3 != ''">
        or title like concat('%', #{keyword3}, '%')
      </if>
    </where>
    order by board_id desc
  </select>

  <!-- foreach를 사용하면 값 개수 만큼 SQL 코드를 반복적으로 생성할 수 있다.  -->
  <select id="select2" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    <where> 1=0
      <foreach collection="keywords" item="keyword">
        or title like concat('%', #{keyword}, '%')
      </foreach>
    </where>
    order by board_id desc
  </select>
  
</mapper>

 

 

Dynamic SQL - foreach 태그의 필요성
package com.eomcs.mybatis.ex04.e;

import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색어1? ");
    String keyword1 = keyboard.nextLine();

    System.out.print("검색어2? ");
    String keyword2 = keyboard.nextLine();

    System.out.print("검색어3? ");
    String keyword3 = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/e/mybatis-config.xml")).openSession();

    // 여러 개의 검색어로 데이터를 찾을 때
    // => 최대 3개의 검색어로 제한하는 경우
    HashMap<String,Object> params = new HashMap<>();
    params.put("keyword1", keyword1);
    params.put("keyword2", keyword2);
    params.put("keyword3", keyword3);

    // if 태그를 사용하는 방식의 한계는
    // - 조건의 개수가 고정된다.
    // - 즉 if 태그의 개수만큼만 조건을 검사할 수 있다.
    // - 조건 개수를 늘리려면 if 태그를 추가해야 한다.
    // 해결책?
    // - foreach 태그를 사용하라!
    // 
    List<Board> boards = sqlSession.selectList("BoardMapper.select1", params);

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

    sqlSession.close();
  }

}

 

 

Dynamic SQL - foreach 태그의 활용
package com.eomcs.mybatis.ex04.e;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);

    ArrayList<String> keywords = new ArrayList<>();

    while (true) {
      System.out.print("검색어?(빈 문자열: 입력 완료!) ");
      String keyword = keyboard.nextLine();
      if (keyword.length() == 0) {
        break;
      }

      keywords.add(keyword);
    }

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/e/mybatis-config.xml")).openSession();

    // 값을 여러 개 넘길 때는 항상 맵에 담아서 넘겨라!
    HashMap<String,Object> params = new HashMap<>();
    params.put("keywords", keywords);

    // foreach 태그를 사용하면 
    // - 값의 개수 만큼 SQL 코드를 반복해서 생성할 수 있다.
    // 
    List<Board> boards = sqlSession.selectList("BoardMapper.select2", params);

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

    sqlSession.close();
  }

}

 

ex04/f/BoardMapper.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="BoardMapper">
  
  <!-- 게시글의 첨부파일 입력 -->
  <insert id="insert1" parameterType="attachFile">
    insert into x_board_file(file_path, board_id)
    values(#{filePath}, #{boardNo})
  </insert>
  
  <!-- foreach 태그를 사용하여 여러 개의 첨부파일을 한 번에 입력하기 -->
  <insert id="insert2" parameterType="map">
    insert into x_board_file(file_path, board_id)
    values 
    <foreach collection="files" item="attachFile" separator="," >
      (#{attachFile.filePath}, #{boardNo})
    </foreach>
  </insert>
  
  <!-- 위의 코드는 다음의 자바 코드와 같은 의미다.
    ArrayList<AttachFile> files = (ArrayList<AttachFile>)map.get("files");
    StringBuilder strBuilder = new StringBuilder();
    strBuilder.append("insert into x_board_file(file_path, board_id) ");
    strBuilder.append("values ");
    int count = 0;
    for (AttachFile attachFile : files) {
      if (count > 0) {
        strBuilder.append(",");
      }
      strBuilder.append("(" + attachFile.getFilePath() + ", " + map.get("boardNo") + ")");
    }
   -->

</mapper>

 

 

insert 문에 foreach를 사용할 필요성
package com.eomcs.mybatis.ex04.f;

import java.util.ArrayList;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;

public class Exam0110 {

  public static void main(String[] args) throws Exception {

    Scanner keyboard = new Scanner(System.in);

    System.out.print("게시글 번호? ");
    int boardNo = Integer.parseInt(keyboard.nextLine());

    ArrayList<AttachFile> files = new ArrayList<>();

    while (true) {
      System.out.print("첨부파일?(빈 문자열: 입력 종료) ");
      String input = keyboard.nextLine();
      if (input.length() == 0) {
        break;
      }
      files.add(new AttachFile(boardNo, input));
    }

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/f/mybatis-config.xml")).openSession(true);

    // 게시글의 첨부파일을 저장하기
    // - List 에 보관된 개수만큼 반복해서 insert를 실행한다.
    // - SQL을 실행한다는 것은 DBMS에 SQL 실행을 요청한다는 의미다.
    // - 여러 번 실행한다는 것은 DBMS에 여러 번 요청한다는 의미다.
    // - 즉 네트워크 사용이 증가한다.
    // 
    // 여러 개의 데이터 입력을 한 번에 처리하는 방법은 없을까?
    // - insert 를 한 번만 요청하면 된다.
    // 
    int count = 0;
    for (AttachFile file : files) {
      count += sqlSession.insert("BoardMapper.insert1", file);
    }
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    sqlSession.close();
  }
}

 

package com.eomcs.mybatis.vo;

public class AttachFile {
  int fileNo;
  String filePath;
  int boardNo;

  public AttachFile() {
  }

  public AttachFile(int boardNo, String filePath) {
    this.boardNo = boardNo;
    this.filePath = filePath;
  }

  public int getFileNo() {
    return fileNo;
  }
  public void setFileNo(int fileNo) {
    this.fileNo = fileNo;
  }
  public String getFilePath() {
    return filePath;
  }
  public void setFilePath(String filePath) {
    this.filePath = filePath;
  }
  public int getBoardNo() {
    return boardNo;
  }
  public void setBoardNo(int boardNo) {
    this.boardNo = boardNo;
  }
}

 

 

insert 문에 foreach를 사용하기
package com.eomcs.mybatis.ex04.f;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;

public class Exam0120 {

  public static void main(String[] args) throws Exception {

    Scanner keyboard = new Scanner(System.in);

    System.out.print("게시글 번호? ");
    int boardNo = Integer.parseInt(keyboard.nextLine());

    ArrayList<AttachFile> files = new ArrayList<>();

    while (true) {
      System.out.print("첨부파일?(빈 문자열: 입력 종료) ");
      String input = keyboard.nextLine();
      if (input.length() == 0) {
        break;
      }
      files.add(new AttachFile(boardNo, input));
    }

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/f/mybatis-config.xml")).openSession(true);

    // insert 문을 만들 때 사용할 값을 Map 에 담는다.
    HashMap<String,Object> params = new HashMap<>();
    params.put("boardNo", boardNo);
    params.put("files", files);

    // 한 번에 여러 개의 값을 insert 하는 방법?
    // - 다음과 같이 여러 개의 값을 한 번에 저장하는 insert 문을 생성한다.
    //     insert into x_board_file(file_path, board_id)
    //     values (파일명, 게시글번호),(파일명, 게시글번호),(파일명, 게시글번호),...
    // - 위와 같이 만든 insert 문장 한 개를 실행한다.
    //   즉 이것은 DBMS에 한 번만 요청한다는 의미다.
    // 
    int count = sqlSession.insert("BoardMapper.insert2", params);
    System.out.printf("%d 개의 데이터를 입력 했음!\n", count);

    sqlSession.close();
  }
}

 

 

ex04/g/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <!-- 검색어로 게시글 찾기 like 연산자 사용 -->
  <select id="select1" resultMap="BoardMap" parameterType="string">
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where title like concat('%', #{keyword}, '%')
  </select>
  
  <!-- like 연산자에서 사용할 값을 bind 태그로 준비하기
    문법:   
         <bind
         name="변수명"
         value="변수에 저장할 값을 만드는 표현식"/>
    _parameter:
         => parameterType 으로 넘어 오는 값을 가리키는 변수명
    변수 사용법:
         => 이전에 파라미터의 값을 사용하듯이 #{변수명} 문법을 사용하면 된다.
  -->
  
  <select id="select2" resultMap="BoardMap" parameterType="string">
    <bind name="pattern1" value="'%' + _parameter + '%'"/>
    select 
      board_id,
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where title like #{pattern1}
  </select>
</mapper>

 

 

bind 태그 사용법 - 사용 전
package com.eomcs.mybatis.ex04.g;

import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {

    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/g/mybatis-config.xml")).openSession();

    List<Board> boards = sqlSession.selectList("BoardMapper.select1", keyword);

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

    sqlSession.close();
  }

}

 

 

bind 태그 사용법 - 사용 후
package com.eomcs.mybatis.ex04.g;

import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {

    Scanner keyboard = new Scanner(System.in);

    System.out.print("검색어? ");
    String keyword = keyboard.nextLine();

    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex04/g/mybatis-config.xml")).openSession();

    // 메서드를 실행할 때 넘겨준 값으로 
    // mybatis 는 <bind> 태그를 사용하여 like 연산에 사용할 값을 준비한다.
    // 
    List<Board> boards = sqlSession.selectList("BoardMapper.select2", keyword);

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

    sqlSession.close();
  }

}

 

 

com.eomcs.mybatis.ex05

 

 

ex05/a/BoardMapper.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="BoardMapper">
  
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/> 
    <!--  
    <result column="title" property="title"/>
    -->
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>
  
  <resultMap type="AttachFile" id="AttachFileMap">
    <id column="board_file_id" property="fileNo"/>
    <result column="file_path" property="filePath"/>
    <result column="board_id" property="boardNo"/>
  </resultMap>
                              
  <resultMap type="Board" id="BoardWithAttachFilesMap">
    <id column="board_id" property="no"/> 
    
    <!-- 테이블 조인을 수행한 경우 컬럼 이름과 프로퍼티 이름이 같더라도 생략하면 안된다. -->  
    <result column="title" property="title"/>

    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
    
    <collection property="attachFiles" ofType="AttachFile">
	    <id column="board_file_id" property="fileNo"/>
	    <result column="file_path" property="filePath"/>
	    <!-- 조인한 자식 테이블의 데이터가 없으면 AttachFile 객체를 생성하지 않는다.
	         size 가 0인 List 객체를 리턴할 것이다.
	         주의!
	         다음과 같이 자식 테이블의 값을 담을 컬럼을 지정할 때 
	         그 컬럼의 값이 NULL 아니라면 
	         자식 테이블의 데이터가 없더라도 그 값을 담기 위해 자바 객체는 무조건 생성된다.
	         그래서 최소 size가 1인 List 객체를 리턴한다. 
	    <result column="board_id" property="boardNo"/>
	     -->
    </collection>
  </resultMap>
  
  <select id="selectBoard" resultMap="BoardMap" parameterType="int">
    select 
      board_id, 
      title,    
      contents,
      created_date, 
      view_count  
    from x_board
    where board_id=#{no}
  </select>
  
  <select id="selectFiles" resultMap="AttachFileMap" parameterType="int">
    select 
      board_file_id,
      file_path,
      board_id
    from x_board_file
    where board_id=#{no}
  </select>
  
  <select id="selectBoard2" resultMap="BoardWithAttachFilesMap" parameterType="int">
    select 
      b.board_id, 
      b.title,    
      b.contents,
      b.created_date, 
      b.view_count,
      bf.board_file_id,
      bf.file_path  
    from x_board b
      left outer join x_board_file bf on b.board_id=bf.board_id
    <if test="no != null">
      where b.board_id=#{no}
    </if>
  </select>
</mapper>

 

 

조인 데이터 가져오기 - 각 테이블의 데이터를 별도로 가져오기
package com.eomcs.mybatis.ex05.a;

import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;
import com.eomcs.mybatis.vo.Board;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);
    System.out.print("게시글 번호? ");
    int no = Integer.parseInt(keyboard.nextLine());
    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex05/a/mybatis-config.xml")).openSession();

    Board b = sqlSession.selectOne("BoardMapper.selectBoard", no);

    System.out.println("[게시글 상세보기]");
    System.out.printf("번호: %d\n", b.getNo());
    System.out.printf("제목: %s\n", b.getTitle());
    System.out.printf("내용: %s\n", b.getContent());
    System.out.printf("등록일: %s\n", b.getRegisteredDate());
    System.out.printf("조회수: %d\n", b.getViewCount());

    System.out.println("첨부파일:");
    List<AttachFile> files = sqlSession.selectList("BoardMapper.selectFiles", b.getNo());

    for (AttachFile f : files) {
      System.out.printf("  %d - %s\n", f.getFileNo(), f.getFilePath());
    }

    sqlSession.close();
  }

}

 

 

조인 데이터 가져오기 - 한 번의 질의로 Board 객체에 AttachFile 객체의 목록을 담아서 리턴 받기
package com.eomcs.mybatis.ex05.a;

import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;
import com.eomcs.mybatis.vo.Board;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    Scanner keyboard = new Scanner(System.in);
    System.out.print("게시글 번호? ");
    int no = Integer.parseInt(keyboard.nextLine());
    keyboard.close();

    SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
        "com/eomcs/mybatis/ex05/a/mybatis-config.xml")).openSession();

    // 게시글 데이터를 가져올 때 첨부 파일 데이터도 포함해서 가져올 수 있다.
    // => 테이블 조인 기법을 사용한다.
    // => 도메인 객체의 포함 관계를 활용한다.
    // 
    Board b = sqlSession.selectOne("BoardMapper.selectBoard2", no);

    System.out.println("[게시글 상세보기]");
    System.out.printf("번호: %d\n", b.getNo());
    System.out.printf("제목: %s\n", b.getTitle());
    System.out.printf("내용: %s\n", b.getContent());
    System.out.printf("등록일: %s\n", b.getRegisteredDate());
    System.out.printf("조회수: %d\n", b.getViewCount());

    System.out.println("첨부파일:");

    for (AttachFile f : b.getAttachFiles()) {
      System.out.printf("  %d - %s\n", f.getFileNo(), f.getFilePath());
    }

    sqlSession.close();
  }

}

 

 

조인 데이터 가져오기 - 여러 개의 조인 데이터 가져오기
package com.eomcs.mybatis.ex05.a;

import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;
import com.eomcs.mybatis.vo.Board;

public class Exam0130 {

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

    // 게시글 데이터를 가져올 때 첨부 파일 데이터도 포함해서 가져올 수 있다.
    // => 테이블 조인 기법을 사용한다.
    // => 도메인 객체의 포함 관계를 활용한다.
    // 
    List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard2");

    for (Board b : boards) {
      System.out.printf("번호: %d\n", b.getNo());
      System.out.printf("제목: %s\n", b.getTitle());
      System.out.printf("내용: %s\n", b.getContent());
      System.out.printf("등록일: %s\n", b.getRegisteredDate());
      System.out.printf("조회수: %d\n", b.getViewCount());

      System.out.printf("첨부파일(%d):\n", b.getAttachFiles().size());

      //      if (b.getAttachFiles().size() == 1 &&
      //          b.getAttachFiles().get(0).getFileNo() == 0) {
      //        System.out.println("  첨부파일이 없습니다!");
      //        continue;
      //      }

      for (AttachFile f : b.getAttachFiles()) {
        System.out.printf("  %d - %s\n", f.getFileNo(), f.getFilePath());
      }

      System.out.println("-----------------------------------------------------");
    }
    sqlSession.close();
  }

}