• Home
  • About
    • Young's Github Pages photo

      一日不作一日不食

    • About
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Java EE 정리 26

03 Apr 2019

Reading time ~5 minutes

Java EE 정리 26 - Framework, MyBatis(1)


Framework

  • 자주 사용될 기능을 미리 구현해 놓은 것
    • Library
      • 생명주기를 개발자가 관리
        • new를 개발자가 함
      • 제공하는 기능을 변경하지 않고 그대로 사용
    • Framework
      • 생명주기를 Framework가 관리한다.
        • new를 개발자가 안함
      • 제공하는 기능을 개발자가 상황에 맞게 변경하여 사용한다.
  • 프레임워크를 사용하면 생산성이 향상된다.
  • 최소한의 품질보장

01

MyBatis 설치

02

  • MyBatis Github
  • WEB-INF/lib에 jar파일을 넣어 설치한다.

03

MyBatis

  • DB Mapper Framework
  • iBATIS(Apache) -> myBATIS(google) -> MyBatis로 발전
    • iBATIS 땐 auto commit
    • MyBatis는 auco commit을 지원하지 않는다.
  • 다양한 언어에서 사용 가능하다(Cross Platform, Multi Platform)
    • Java, .NET
  • XML에 쿼리문을 정의하고 사용하는 방식
  • Java에서 지원하는 PreparedStatement, Procedure를 손쉽게 사용할 수 있도록 해줌
  • JDBC의 불편함(중복코드)을 대폭 개선
  • Domain과 VO
    • Domain
      • 원래 DB Table Column 한개를 뜻함
      • VO처럼 작성하나 VO와는 구분하여 사용
      • 조회한(SELECT) 결과를 저장할 때 사용하는 객체
    • VO
      • 값을 가진 객체
        • INSERT할 때 추가하는 값
        • UPDATE할 때 변경하는 값
        • WHERE절에 들어가는 값
  • 구조

04

MyBatis 사용법

  • 설정용 xml 작성(mybatis_config.xml)
    • Building SqlSessionFactory from XML 참고
    • driver, url, username, password를 바꿔준다.
<?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">
  <!-- MyBatis의 환경설정(연동할 DB설정)을 수행
      설정 정보를 properties에 넣고 하는 것과,
      설정 정보를 직접 Hard Coding하는 방법이 존재
   -->
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="oracle.jdbc.OracleDriver"/>
        <property name="url"  value="jdbc:oracle:thin:@localhost:1521:orcl"/>
        <property name="username" value="scott"/>
        <property name="password" value="tiger"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 쿼리문을 가진 XML을 연결 -->
  <mappers>
    <mapper resource="date0403/mapper/dept_mapper.xml"/>
  </mappers>
</configuration>
  • Mapper xml 작성(OOO_mapper.xml)
    • 연결된 서로 다른 맵퍼에 동일한 id가 존재할 수 있음
      • namespace로 XML내에서 중복된 id를 사용할 수 있도록 구분
    • 쿼리 뒤에 절대 ‘;’를 붙이지 않는다.
<?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="kr.co.sist">
  <select id="selectAllDept" resultType="date0403.domain.Dept">
    select deptno, dname, loc from dept
  </select>
</mapper>
  • 설정용 xml과 연결할 Stream 사용
    • 한글을 사용할 수 있으므로 16bit Stream(Reader) 사용
    • 경로 입력시 src하위 경로만(패키지명부터) 입력해주면 됨
Reader r = Resources.getResourceAsReader("설정용xml경로");
  • MyBatis Framework(SqlSessionFactoryBuilder) 생성
SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
  • 설정파일과 연결된 Stream을 할당하여 DB가 연동된 객체(SqlSessionFactory) 얻기
SqlSessionFactory ssf = ssfb.build(r);
  • MyBatis Handler(SqlSession)를 얻기
    • Handler는 쿼리를 가진 XML의 노드를 id로 찾아 parsing하여 쿼리를 수행하고 결과를 얻는 일을 수행
SqlSession ss = ssf.openSession();

// 추가
ss.insert("namespace.id",VO); // namespace는 생략가능
// 변경
ss.update("id", VO);
// 삭제
ss.delete("id", VO);

// 한행 조회
ss.selectOne("id", VO); // Domain 반환
// 여러행 조회
ss.selectList("id", VO); // List<Domain> 반환
  • MyBatis 사용 예
package date0403.domain;

/**
* 조회한 컬럼의 값을 저장하는 VO를 Domain이라고 한다.
*/
public class Dept {
      private int deptno;
      private String dname, loc;
      // 기본 생성자만 필요, 자동 생성되므로 생성자를 만들 필요가 없다
      // (최근 버전 3.5.0은 인자있는 생성자만 있어도 된다)
      // 도메인은 생성자를 따로 안만들어도 된다.
...
public class UseMyBatis {
      
      public void selectAllDept() throws IOException {
            // 1. 환경설정 xml에 스트림을 연결
            Reader reader =  Resources.getResourceAsReader("date0403/mybatis_config.xml");
            // 2. MyBatis Framework 생성
            SqlSessionFactoryBuilder ssfb = new  SqlSessionFactoryBuilder();
            // 3. MyBatis Framework과 DB연동한 객체를 얻기(Factory객체를 하나로 관리하면 좋다)
            SqlSessionFactory ssf = ssfb.build(reader);

            if (reader != null) { // Reader는 build후 끊어준다.
                  reader.close();
            }

            // 4. MyBatis Handler 얻기
            SqlSession ss = ssf.openSession();
            // 5. Handler를 사용하여 DB작업을 수행
            List<Dept> list = ss.selectList("kr.co.sist.selectAllDept"); 
            // id가 유일하다면 namespace 생략가능
      
            Dept d = null;
            for(int i=0; i<list.size(); i++) {
                  d = list.get(i);
                  System.out.println(d.getDeptno()+"/"
                              +d.getDeptno()+"/"+d.getDname()+"/"+d.getLoc());
            }

            // 6. 사용이 종료된 SqlSession을 닫는다.
            ss.close();
      }
      
      public static void main(String[] args) {
            UseMyBatis umb = new UseMyBatis();
            try {
                  umb.selectAllDept();
            } catch (IOException e) {
                  e.printStackTrace();
            }
      }
}

05

MyBatis - Mapper 작성법

  • 값으로는 ${ VO getter }, #{ VO getter }를 사용한다.
    • $는 쿼리로 대체된다.(쿼리문으로 반영됨)
      • 컬럼명, 테이블명
    • #은 바인드 변수로 대체된다.
  • 추가
<insert id="Handler에서 찾을 ID" parameterType="패키지명.VO명">
    INSERT INTO 테이블명 (컬럼명1, 컬럼명2, ...) VALUES (값1, 값2, ...)
</insert>
  • 추가 사용
ss.insert("id", VO);
  • 업데이트
<update id="Handler에서 찾을 ID" parameterType="패키지명.VO명">
    UPDATE 테이블명
    SET 컬럼명=값
    WHERE 컬럼명=값
</update>
  • 업데이트 사용
int cnt = ss.update("id",VO); // 업데이트를 수행한 행의 수를 반환
  • 삭제
<delete id="Handler에서 찾을 ID" parameterType="패키지명.VO명">
    DELETE FROM 테이블명
    WHERE 컬럼명=값
</delete>
  • 삭제 사용
int cnt = ss.delete("id",VO); // 삭제된 행의 수를 반환
  • 주석
    • 쿼리부분에 SQL주석을 달 수 있다. (–, /* */)
    • ”–“주석을 사용하면 줄바뀐 아래 쿼리들까지 주석처리된다.
      • MyBatis에서 “–“주석을 사용하지 말 것
  • 조회
    • VO의 값으로 값을 설정하고 조회결과는 Domain에 저장한다.
<SELECT id="id" parameterType="VO" resultType="Domain">  
    SELECT 컬럼명, ...
    FROM 테이블명
    WHERE 컬럼명=값
</SELECT>
  • 한행 조회
Domain d = ss.selectOne("id", VO);
  • 여러행 조회
List<Domain> list = ss.selectList("id",VO);
  • MyBatis insert 예
public class UseMyBatis {
      // SesstionFactory를 만든는 Method를 별도로 생성
      public SqlSessionFactory getSessionFactory() throws IOException {
            // 1. 환경설정 xml에 스트림을 연결
            Reader reader =  Resources.getResourceAsReader("date0403/mybatis_config.xml");
            // 2. MyBatis Framework 생성
            SqlSessionFactoryBuilder ssfb = new  SqlSessionFactoryBuilder();
            // 3. MyBatis Framework과 DB연동한 객체를 얻기(Factory객체를  하나로 관리)
            SqlSessionFactory ssf = ssfb.build(reader);
            
            if (reader != null) {
                  reader.close();
            }
            
            return ssf;
      }
...
package date0403.vo; // VO패키지
public class Dept { // Domain과 VO는 다른 패키지에 생성
      
      private int deptno;
      private String dname, loc;
      // VO값을 넣기 위해 인자있는 생성자와, 값을 사용하기 위해 getter 생성
      ...
...
  <!-- dept_mapper.xml에 statement 추가 -->
  <insert id="insertCpDept" parameterType="date0403.vo.Dept">
      INSERT INTO cp_dept(deptno, dname, loc)
      VALUES(#{deptno}, #{dname}, #{loc})
  </insert>
</mapper>
public class UseMyBatis {
      ...
      public void insertCpDept(date0403.vo.Dept d_vo) throws  IOException, SQLException {
            // 4. MyBatis Handler 얻기
            SqlSession ss = getSessionFactory().openSession();
            
            // 5. Handler 사용하여 DB작업 수행
            int cnt = ss.insert("insertCpDept", d_vo);
            System.out.println("추가 작업");
            
            ss.commit();
      }
...
      public static void main(String[] args) {
            UseMyBatis umb = new UseMyBatis();
            try {
                  date0403.vo.Dept dvo = new  date0403.vo.Dept(12,"SI개발부","나주");
                  umb.insertCpDept(dvo);
            } catch (IOException e) {
                  e.printStackTrace();
            } catch (SQLException e) {
                  e.printStackTrace();
            }
      }
}

06

  • MyBatis update 예
...
  <!-- dept_mapper.xml -->
  <update id="updateCpDept" parameterType="date0403.vo.Dept">
      UPDATE cp_dept
      SET          dname=#{dname}, loc=#{loc}
      WHERE  deptno=#{deptno}
  </update>
</mapper>
      // UseMyBatis
      public void updateCpDept(date0403.vo.Dept d_vo) throws  IOException, SQLException {
            // 4. MyBatis Handler 얻기
            SqlSession ss = getSessionFactory().openSession();
            
            // 5. Handler 사용하여 DB작업 수행
            int cnt = ss.update("updateCpDept", d_vo);
            System.out.println("업데이트 성공:"+cnt);
            
            ss.commit();
      }
...
      public static void main(String[] args) {
            UseMyBatis umb = new UseMyBatis();
            try {
                  date0403.vo.Dept dvo = new  date0403.vo.Dept(12,"SI개발부부","나주");
                  umb.updateCpDept(dvo);
            } catch (IOException e) {
                  e.printStackTrace();
            } catch (SQLException e) {
                  e.printStackTrace();
            }
      }
}

07

  • MyBatis delete 예
...
  <delete id="deleteCpDept" parameterType="int">
      DELETE FROM cp_dept
      WHERE deptno=#{deptno}
  </delete>
</mapper>
...
      // UseMyBatis
      public void deleteCpDept(int deptno) throws  SQLException,IOException {
            // 4. MyBatis Handler 얻기
            SqlSession ss = getSessionFactory().openSession();
            
            // 5. Handler를 사용해서 DB작업을 수행
            int cnt = ss.delete("deleteCpDept", deptno);
            ss.commit();
            
            if (cnt == 1) {
                  System.out.println(deptno+"번 부서정보를  삭제했습니다.");
            } else {
                  System.out.println("해당 부서는 존재하지 않습니다.");
            }
      }
      
      public static void main(String[] args) {
            UseMyBatis umb = new UseMyBatis();
            try {
                  umb.deleteCpDept(11);
            } catch (IOException e) {
                  e.printStackTrace();
            } catch (SQLException e) {
                  e.printStackTrace();
            }
      }
}

08



Java EEMyBatis