menu

MyBatis

MyBatis

MyBatis란?

MyBatis란 객체지향 언어인 자바의 관계형 데이터 베이스 프로그래밍을 좀더 쉽게 할 수 있도록 도와주는 프레임워크입니다.

Framwork

뼈대근간을 이루는 코드들의 묶음

프로그램의 기본 흐름이나 구조를 미리 정해놓고 이 구조에 자신의 코드를 추가하는 방식으로 개발할 수 있도록 하는 프로그래밍의 기본 틀을 의미.

개발에 필요한 구조가 사전에 제공(대체로 다운로드 받을 수 있다)되고, 여기에 필요한 부분을 개발자가 구현해서 조립하는 형태로 개방이 진행된다.

Framwork를 사용할 경우 장점

  • 개발 기간을 단축할 수 있다
  • 팀 안에서 개인의 능력 차이를 극복하고 일정한 품질을 보장할 수 있다.

#01. 환경설정

1) 라이브러리 설정

다음의 항목들을 Eclipse의 Java Build Path에 설정한다.

2) 설정파일 구성

study.java.mybatis 패키지를 생성하고 그 안에 mybatis_config.xml파일을 생성한다.

패키지 이름과 파일명은 임의로 변경 가능

mybatis_config.xml

https://mybatis.org/mybatis-3/ko/getting-started.html에서 설정파일의 기본 원형을 가져와 생성한 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>
      <property name="hostname" value="호스트이름" />
      <property name="portnumber" value="포트번호" />
      <property name="database" value="DB이름" />
      <property name="username" value="사용자계정" />
      <property name="password" value="비밀번호" />
  </properties>

  <!-- MySQL 접속 객체 구성 -->
  <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="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

before

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration=
<configuration>=
</configuration>

after

${dirver}라고 된 위치에 MySQL JDBC 8의 driver 이름인 com.mysql.cj.jdbc.Driver을 적용한다.

&{url}로 위치는 아래와 같은 형식의 접속 문자열을 구성해야 한다.

​ jdbc:mysql://localhost:3306/myschool?characterEncoding=UTF8&serverTimezone=UTC

localhost(host이름), 3306(포트번호), myschool(db이름)을 각각 별도의 변수로 사용하기 위해 다음과 같이 URL을 구성

​ jdbc:mysql://${hostname}:${portnumber}/${database}?characterEncoding=UTF8&serverTimezone=UTC

<mappers>태그에 속한 항목을 일단 삭제한다.

#02. 데이터 조회 결과가 저장될 자료구조 정의

study.java.model패키지를 추가하고 그 안에 테이블단위 혹은 Join문이 구성되는 단위마다 Beans클래스를 정의한다.

MyBatis를 위한 클래스에서는 생성자를 정의할 필요가 없다. 값의 할당은 setter 메서드를 사용한다.

packege study.java.model;

public class Department {
  private int deptno;
  private String dname;
  private String loc;

  /** getter,setter, toString정의 */
  // 강사님은 말하셨지 겟터셋터 투스트링 안해도 된다고
}

Lombok.jar 다운로드

[다운로드]

Lombok.jar파일을 다운로드 받고 빌드패스 설정 후 Lombok.jar파일을 열어 이클립스 실행파일의 위치를 넣은 후 Install 버튼 클릭 이클립스 종료후 재실행

Lombok.jar파일 설정 완료

테이블 멤버변수 조회 개꿀팁

테이블안의 컬럼 조회

SELECT concat('private String', LOWER(COLUMN_NAME), ';') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'student';

student테이블의 멤버변수 조회

SQL에서 실행해야한다.

select concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'student'; 

데이터베이스 이름을 따로 넣어 조회

select concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA= 'myschool' AND TABLE_NAME = 'student'; 
+---------------------------------------------------------------------------------------+
| concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';') |
+---------------------------------------------------------------------------------------+
| private int studno;                                                                   |
| private String name;                                                                  |
| private String userid;                                                                |
| private int grade;                                                                    |
| private String idnum;                                                                 |
| private String birthdate;                                                             |
| private String tel;                                                                   |
| private int height;                                                                   |
| private int weight;                                                                   |
| private int deptno;                                                                   |
| private int profno;                                                                   |
+---------------------------------------------------------------------------------------+

교수테이블 멤버변수 조회

select concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';')
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_SCHEMA= 'myschool' AND TABLE_NAME = 'professor';

--------------------------------------------------
+---------------------------------------------------------------------------------------+
| concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';') |
+---------------------------------------------------------------------------------------+
| private int profno;                                                                   |
| private String name;                                                                  |
| private String userid;                                                                |
| private String position;                                                              |
| private int sal;                                                                      |
| private String hiredate;                                                              |
| private int comm;                                                                     |
| private int deptno;                                                                   |
+---------------------------------------------------------------------------------------+

03. Mapper XML 정의

1) mybatis_config.xml 파일에 생성할 Mapper 경로 정의

<mappers>태그 안에 생성할 파일의 경로를 명시해야 한다.

<mappers>
    <mapper resource="study/java/mybatis/mappers/DepartmentMapper.xml" />
</mappers>mappers>

2) 명시한 Mapper 파일 생성

study.java.mybatis.mappers 패키지를 만들고 그 안에 Beans이름Mapper.xml형식으로 파일을 생성한다.

DepartmentMapper.xml

아래의 Mapper 원형 구문을 기본형으로 삼아 사용하되 구현하고자 하는 SQL문의 성격에 따라 추가적으로 <select>, <insert>, <update>, <delete>태그를 추가할 수 있다.

{Beans}라고 명시한 부분은 사용하고자 하는 클래스 이름으로 수정하세요

각각의 태그가 하나의 DAO 메서드 역할을 하고 id속성값이 메서드 이름이 된다.

SQL문 안에서 parameterType으로 설정된 객체의 멤버변수를 통해 getter 메서드를 호출할 수 있다.

SELECT deptno, dname, loc FROM department WHERE deptno=#{deptno}

Mapper 원형

<?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="{Beans}Mapper"> // Interface나 클래스이름

    <!-- Beans 클래스의 객체이름(id) 클래스이름(type) 명시한다. -->
    <resultMap id="SELECT결과가 저장될 객체이름" type="{Beans}의 패키지.클래스이름">
        <!-- Beans 멤버변수(property)이름과 대상 테이블의 컬럼(column) 연결한다. -->
        <result property="{Beans}의 멤버변수1" column="연결될 테이블컬럼1" />
        <result property="{Beans}의 멤버변수2" column="연결될 테이블컬럼2" />
        <result property="{Beans}의 멤버변수3" column="연결될 테이블컬럼3" />
    </resultMap>

    <!-- 단일행 조회를 위한 기능 정의 -->
    <select id="selectItem"
            parameterType="{Beans}의 패키지.클래스이름" // 파라미터타입은 무조건 빈즈의 풀네임
            resultMap="<resultMap>에서 정의한 SELECT결과가 저장될 객체이름">
        <!--  안에서 처리할 SQL문을 명시한다. -->
    </select>

    <!-- 다중행 조회를 위한 기능 정의 -->
    <select id="selectList"
            parameterType="{Beans}의 패키지.클래스이름"
            resultMap="<resultMap>에서 정의한 SELECT결과가 저장될 객체이름">
        <!--  안에서 처리할 SQL문을 명시한다. -->
    </select>

    <!-- 데이터  조회를 위한 기능 정의 -->
    <select id="selectCount"
            parameterType="{Beans}의 패키지.클래스이름"
            resultType="int">
        <!--  안에서 처리할 SQL문을 명시한다. -->
    </select>

    <!-- 데이터 저장을 위한 기능 정의 -->
    <insert id="insertItem"
            parameterType="{Beans}의 패키지.클래스이름"
            useGeneratedKeys="true"
            keyProperty="테이블의 PK컬럼과 맵핑되는 JavaBeans의 멤버변수이름">
        <!--  안에서 처리할 SQL문을 명시한다. -->
    </insert>

    <!-- 데이터 삭제를 위한 기능 정의 -->
    <delete id="deleteItem" parameterType="{Beans}의 패키지.클래스이름">
        <!--  안에서 처리할 SQL문을 명시한다. -->
    </delete>

    <!-- 데이터 갱신을 위한 기능 정의 -->
    <update id="updateItem" parameterType="{Beans}의 패키지.클래스이름">
        <!--  안에서 처리할 SQL문을 명시한다. -->
    </update>

</mapper>

트랜젝션

하나의 프로그램에서 수행되는 여러개의 SQL문들

에러코드 예시

  1. DepartmentMapper의 parameterType의 파일주소가 잘못 표기
Exception in thread "main" java.lang.ExceptionInInitializerError
  at DepartmentSelectOne.main(DepartmentSelectOne.java:9)
Caused by: org.apache.ibatis.exceptions.PersistenceException: 
### Error building SqlSession.
### The error may exist in study/java/mybatis/mappers/DepartmentMapper.xml
### The error occurred while processing mapper_resultMap[departmentMap]
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'study/java/mybatis/mappers/DepartmentMapper.xml'. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'.  Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent
  at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
  at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:52)
  at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:36)
  at study.java.mybatis.MyBatisConnectionFactory.<clinit>(MyBatisConnectionFactory.java:29)
  ... 1 more
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'study/java/mybatis/mappers/DepartmentMapper.xml'. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'.  Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent
  at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:121)
  at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:98)
  at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:50)
  ... 3 more
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'study/java/mybatis/mappers/DepartmentMapper.xml'. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'.  Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent
  at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:122)
  at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:94)
  at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:374)
  at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:119)
  ... 5 more
Caused by: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'.  Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent
  at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:118)
  at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:76)
  at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:137)
  at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:130)
  at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:120)
  ... 8 more
Caused by: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'.  Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent
  at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:120)
  at org.apache.ibatis.builder.BaseBuilder.resolveAlias(BaseBuilder.java:149)
  at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:116)
  ... 12 more
Caused by: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent
  at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:200)
  at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:89)
  at org.apache.ibatis.io.Resources.classForName(Resources.java:261)
  at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:116)
  ... 14 more
  1. SelectList 메인문의 데이터 조회값 오타
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for DepartmentMappers.selectList
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for DepartmentMappers.selectList
  at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
  at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149)
  at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
  at DepartmentSelectList.main(DepartmentSelectList.java:15)
Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for DepartmentMappers.selectList
  at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:964)
  at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:755)
  at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:748)
  at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:146)
  ... 2 more

1.

<!-- 데이터 저장을 위한 기능 정의 -->
    <insert id="insertItem"
            parameterType="study.java.model.Department"
            useGeneratedKeys="true"
            keyProperty="deptno">
        INSERT INTO department (
          dname, loc    // <-- "," 미입력과 오타
        ) VALUES ( 
          #{dname}, #{loc}   
        );
    </insert>
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; (
          danmem loc
        ) VALUES ( 
          'JAVA학과', 'JAVA관'
   ' at line 1
### The error may exist in study/java/mybatis/mappers/DepartmentMapper.xml
### The error may involve DepartmentMapper.insertItem-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO department; (          danmem loc         ) VALUES (           ?, ?         );
### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; (
          danmem loc
        ) VALUES ( 
          'JAVA학과', 'JAVA관'
   ' at line 1
  at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
  at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:199)
  at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184)
  at DepartmentInsert.main(DepartmentInsert.java:17)
Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; (
          danmem loc
        ) VALUES ( 
          'JAVA학과', 'JAVA관'
   ' at line 1
  at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
  at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
  at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
  at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
  at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:370)
  at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47)
  at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
  at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
  at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
  at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
  at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197)
  ... 2 more