myBatis

myBatis란

myBatis란 개발자가 지정한 SQL, 프로시저, 고급 매핑을 지원하는 퍼시스턴트 프레임워크이다. JDBC의 상당부분을 자동화해주어 개발을 빠르게 할 수 있도록 도와주며 데이터베이스 관련 설정들도 쉽게 구현할 수 있도록 해준다. 상당히 많은 비율의 회사들이 개발에 myBatis를 사용하고 있으며, 이를 대체할 수 있는 수단으로는 JPA가 있다.

의존성 설정

Spring에서 myBatis를 사용하기 위해 필요한 의존성은 다음과 같다.

  • MyBatis

  • MyBatis Spring

pom.xml에 필요한 의존성 정보를 추가한다.

pom.xml

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.2</version>
</dependency>

버전은 상황에 따라 최신/안정화 버전을 설정한다.

Spring Bean 등록

JdbcTemplate을 사용할 때와 마찬가지로 myBatis를 이용하기 위해서는 Spring Bean을 등록해야 한다. 다음 두 가지의 bean을 root-context.xml에 등록한다.(뷰와 연관이 없기 때문)

  • org.mybatis.spring.SqlSessionFactoryBean myBatis 중앙 제어 도구

  • org.mybatis.spring.SqlSessionTemplate myBatis 명령 실행 도구

root-context.xml

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="연결할 dataSource의 ID"></property>
    <property name="configLocation" value="마이바티스 설정파일 위치"></property>
    <property name="mapperLocations" value="마이바티스 명령(mapper)파일 위치를 패턴으로 기재"></property>
 </bean>

 <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSession"></constructor-arg>
 </bean>

myBatis 기본 설정

myBatis 기본 설정파일은 다음과 같은 DTD 선언과 기본 영역이 필요하다.

<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

</configuration>

선언되지 않은 경우에는 오류가 발생한다.

우리는 myBatisSpring에 붙여서 사용하기 때문에 Spring 설정이 더 중요하다. 따라서 계정 등의 관리 정보는 모두 Spring 설정으로 구현되어 있고, myBatis에서는 크게 할 설정이 없다. 몇 가지 필요한 설정에 대해서 살펴보면 다음과 같다.

  • <settings> 관리 설정

  • <typeAliases> 별칭 설정

특히 별칭 설정이 중요한데, 별칭 설정은 전체 경로를 줄여주는 효과를 가진다. 예를 들어 com.hakademy.test.entity.TestDto라는 클래스가 있을 경우 별칭을 부여하여 testDto와 같이 줄일 수 있다.

샘플 코드는 다음과 같다.

<typeAliases>
    <typeAlias type="com.hakademy.test.entity.TestDto" alias="testDto"/>
</typeAliases>

오타가 발생할 경우 해당 파일을 찾지 못하여 실행하자마자 오류가 발생하므로 주의하도록 한다.

mapper 기본 설정

mapper는 실행 가능한 데이터베이스 명령을 식별 가능한 형태로 보관해두는 파일이다. mapper의 기본 DTD 선언과 영역 설정은 다음과 같다.

<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="영역 별칭">

</mapper>

namespace는 외부에서 접근하기 위한 별칭을 작성하는 곳이며, 다른 namespace와 중복될 경우 오류가 발생한다.

<mapper> 내부에는 다음 설정들을 작성한다.

  • <insert> Create 코드 작성 영역

  • <select> Read 코드 작성 영역

  • <update> Update 코드 작성 영역

  • <delete> Delete 코드 작성 영역

테이블 예시

다음과 같은 테이블과 DTO가 있다고 가정하고 CRUD를 진행한다.

table student

com.hakademy.test.entity.StudentDto.java

package com.hakademy.test.entity;

@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class StudentDto{
    private int no;
    private String name;
    private int score;
    private String reg;
}

편의를 위해 myBatis 설정파일에 다음과 같이 별칭이 등록되어있다고 가정한다.

<typeAliases>
    <typeAlias type="com.hakademy.test.entity.StudentDto" alias="student"/>
</typeAliases>

insert 구문 예시

데이터를 추가하기 위한 insert 구문은 다음과 같다.

<insert id="regist" parameterType="student">
    insert into student values(student_seq.nextval, #{name}, #{score}, sysdate)
</insert>
  • id : 구문을 호출하기 위한 식별자이며 namespace 내에서 유일해야 한다.

  • parameterType : 이 명령을 실행하기 위하여 필요한 데이터의 형태를 1개만 작성할 수 있다.

  • #{name} : student라는 parameterType에 대하여 작업을 수행하므로 student.getName()와 같이 해석된다.

  • #{score} : student라는 parameterType에 대하여 작업을 수행하므로 student.getScore()와 같이 해석된다.

태그 형식이므로 엔터나 띄어쓰기 등이 좀 더 자유롭다.

select 구문 예시

목록을 구하기 위한 select 구문은 다음과 같다.

<select id="list" resultType="student">
    select * from student order by no asc
</select>
  • id : 구문 식별자

  • resultType : 이 명령을 실행했을 때 기대되는 결과물의 형태로 student라고 적을 경우 단일개체, 다중개체 모두 해당된다.

이름으로 검색하는 구문의 예시는 다음과 같다.

<select id="findByName" resultType="student" parameterType="String">
    select * from student where name = #{name} order by no asc
</select>
  • id : 구문 식별자

  • resultType : 결과값의 형태로 이 구문은 student(com.hakademy.test.entity.StudentDto)가 나옴

  • parameterType : 실행에 필요한 데이터는 이름값이므로 string(String)이라고 표기(내장된 별칭에 의해 대소문자 구분하지 않음)

만약 항목과 검색어를 받아서 검색하는 경우에는 다음과 같이 작성할 수 있다.

<select id="find" resultType="student" parameterType="map">
    select * from student where ${type} like '%'||#{keyword}||'%' order by no asc
</select>
  • resultType은 여전히 student이다.

  • parameterType은 map(java.util.Map)이며, 이 때 데이터를 key=value 형태로 첨부하면 이름으로 사용이 가능하다.

  • ${type}은 정적 바인딩으로 값이 그 자리에 그대로 출력되며 parameterType이 map이기 때문에 map.get("type")으로 해석된다.

  • #{keyword}는 동적 바인딩으로 값이 형태에 따라 출력되며 parameterType이 map이기 때문에 map.get("keyword")로 해석된다.

만약 목록과 검색을 한 번에 수행하는 구문을 만들고 싶다면 다음과 같이 조건을 사용할 수 있다.

<select id="searchAndList" resultType="student" parameterType="map">
    select * from student 
    <if test="type != null and keyword != null">
        where ${type} like '%'||#{keyword}||'%'
    </if>
    order by no asc
</select>

myBatis의 조건 구문은 JSTL과 매우 유사한 형태를 보이며, &와 같은 기호들도 xhtml에서 사용하기 힘들기 때문에 단어형 연산도 지원한다.

만약 구문에 부등호처럼 xhtml에서 사용 불가한 기호를 써야 할 경우에는 다음과 같이 작성한다.

<select id="findGreatStudent" resultType="student" parameterType="int">
<![CDATA[
    select * from student where score > #{score}
]]>
</select>

<![CDATA[ ]]> 표시가 있을 경우 사이에 있는 글자들은 모두 일반 글자로 간주되므로 필요할 경우 사용해야 한다.

SqlSession을 이용한 CRUD 수행

myBatis에 만들어 둔 구문을 사용하고 싶다면 sqlSession을 불러와야 한다. SqlSessionTemplate의 상위 형태인 SqlSession으로 저장하여 사용하는것이 일반적이다.

Spring에서는 다음과 같이 사용한다.

@Autowired
private SqlSession sqlSession;

CRUD 명령을 수행하려면 구문의 namespace와 id를 알아야 한다.

<mapper namespace="test">
    <insert id="create" ...>
        insert into...
    </insert>
</mapper>

위의 구문을 부르기 위한 명령은 다음과 같다.

sqlSession.insert("test.create", ...);

sqlSession은 CRUD에 맞게 각각의 명령을 가지고 있으며, 주요 명령은 다음과 같다.

  • insert(C)

    • sqlSession.insert("구문ID", 첨부데이터)

  • select(R)

    • sqlSession.selectOne("구문ID", 첨부데이터) : 단일조회

    • sqlSession.selectList("구문ID", 첨부데이터) : 목록조회

  • update(U)

    • sqlSession.update("구문ID", 첨부데이터)

  • delete(D)

    • sqlSession.delete("구문ID", 첨부데이터)

첨부데이터는 1개만 가능하며, 여러개일 경우 객체 또는 Map<String, Object> 형태로 이름을 부여하여 첨부해야 한다.

DAO를 이용한 CRUD 수행

DAO를 이용하여 CRUD를 수행할 경우에는 DAO에 SqlSession 을 Autowired 하여 사용한다.

Last updated