Mybatis는 데이터베이스 작업을 좀 더 편리하게 해주는 프레임워크이다.
현업에서 자주 쓰이는 프레임워크 임으로 잘 알아두자.


◆ myBatis (마이바티스)

개발자가 설정한 SQL문을 처리하는 JDBC서포트 프레임워크
( 실제 개발과정에서 자주 사용되는 프레임워크중 하나이다. )

  • 데이터베이스와의 연결을 관리 해줌.
  • myBatis는 DBCP라는 Connection Pool을 사용하여 커넥션을 여러 개 생성하여, 관리하기 때문에 그냥 JDBC를 사용하는 것 보다, 작업이 부드럽게 이루어진다.


▶ 라이브러리와 프레임워크의 차이

  • 라이브러리 : 만들어놓은 API들을 불러와서 사용할 수 있게 해주는 클래스들의 집합
  • 프레임워크 : 라이브러리들을 모아서 만든 사용법이 정해진 큰 틀의 라이브러리 집합


◆ myBatis 사용준비

1. 라이브러리 추가

http:www.mybatis.org에서 mybaits zip파일을 다운을 받아서 압축해제 후 mybatis.jar파일과 lib디렉터리 내부의 라이브러리 파일을 추가해주면 된다.
(WEB-INF/lib)


2. WEB-INF안에 xml파일을 추가해서 연결설정

프로젝트 WEB-INF디렉터리에 xml파일을 하나 생성하여 아래와 같이 연결을 설정한다.
mybatis라이브러리 zip파일 내부의 pdf파일을 통해서도 확인이 가능하다.

<?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>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver"
					value="oracle.jdbc.driver.OracleDriver" />
				<property name="url"
					value="jdbc:oracle:thin:@127.0.0.1:1521:xe" />
				<property name="username" value="아이디" />
				<property name="password" value="비밀번호" />
			</dataSource>
		</environment>
	</environments>
</configuration>

※ DB종류와 정보에 따라 입력값(value)이 달라질 수 있다.


3. xml파일을 불러올 InputStream객체 생성

2번에서 만든 xml파일의 경로를 인자로 InputStream객체를 생성한다.

ServletContext application = request.getServletContext();
InputStream is = application.getResourceAsStream("/WEB-INF/만든xml파일명.xml");


4. SqlSessionFactory 객체생성

3번에서 만든 InputStream객체를 인자로 SqlSessionFactory객체를 생성한다.

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
또는
SqlSessionFactoryBuilder sb = new SqlSessionFactoryBuilder();
SqlSessionFactory sf = sb.build(is);


5. SqlSession 객체생성 및 작업

4번에서 만든 SqlSessionFactory객체의 openSession()메서드를 이용하여 SqlSession객체를 생성한다.
이렇게 만들어진 SqlSession객체를 통하여 SQL문을 제어할 수 있다.

SqlSession sql = factory.openSession();
// 중간작업(SQL작업)
sql.close();

실제 작업은 SqlSession객체를 통해서만하기 때문에 3,4번의 작업은 보통 어플리케이션 리스너(서블릿컨텍스트리스너)에서 어플리케이션에 SqlSessionFactory객체까지 만들어두고 올려둔 상태로 진행한다.


◆ SQL 작성 등록

위처럼 Mybatis설정 준비가 됐으면, 이제는 사용할 SQL문을 등록시켜 두어야 한다.

1. SQL문을 등록할 xml파일을 생성한다.

처음 mybatis설정했던 xml파일이 아닌 SQL문을 등록할 새로운 xml파일을 생성시켜둔다.
주의할 점은 WEB-INF디렉터리 내부는 인식할 수 없기 때문에 java Resources안에 새로 패키지를 만들어 넣어준다.


2. SQL문 등록

<?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="show">
	<select id="readOne" parameterType="java.lang.String"
		resultType="java.util.HashMap">
		select * from member
	</select>
	
    <select id="readTwo" parameterType="java.lang.String"
		resultType="java.util.HashMap">
		select name from member
	</select>
</mapper>
  • <mapper> 태그의 namespace
    자바 코드에서 SQL문을 호출할 때 인자로 식별할 이름
  • sql태그의 id
    자바코드에서 “namespace명.sql태그id”를 인자로 호출되기 때문에 이를 식별하기 위한 옵션
  • sql태그의 parameterType
    SQL문을 실행할 때 어떤 타입으로 인자를 넘겨줄 것인지를 설정
  • sql태그의 resultType
    select태그에서 sql명령문의 결과로 받아올 데이터의 타입을 설정한다.
  • 타입의 입력은 전체 클래스명(ex ) java.util.HashMap) 또는 별칭으로도 설정이 가능하다.
  • resultType은 반환타입 설정이기 때문에 <select>에서만 설정이 가능한 옵션이다.
  • <insert>, <select>, <update>등 사용하고자 하는 명령문에 따라 태그를 다르게 설정해서 사용한다.


▶ resultType, parameterType 별칭사용

별칭은 클래스명 전체를 입력하지 않고, 특정 이름을 통해 등록하는 타입이다.
이를 등록하기 위해서는 처음 mybatis연결을 설정했던 xml파일에 아래와 같이 작성하면 된다.

<typeAliases>
    <typeAlias type="java.util.HashMap" alias="hMap" />
    <typeAlias type="java.lang.String" alias="string" />
</typeAliases>

와 같은 작업을 해주면, type에 해당하는 클래스객체를 alias옵션의 이름으로 resultType에 입력할 수 있게 된다. 단, 이미 잡혀있는 별칭도 존재하기 때문에 중복 사용은 불가능하다.
=> 주의할 점은 DB연결태그 위로 써 주어야 한다.

▶ 이미 잡혀있는 typeAlias별칭들

  • java.lang.String = string
  • java.lang.Integer = int / integer
  • java.lang.Double = double
  • java.util.Date = date
  • java.util.HashMap = hashmap
  • java.util.ArrayList = arraylist


▶ SQL문 파라미터 설정

JDBC에서 where문의 들어갈 조건을 설정할 때 썼던 ? 대신에 #{ 변수 }로 설정해준다.

해당 조건의 변수명이 하나인 경우에는 아무거나 써 주어도 의미가 없지만, 여러 개 일 경우 인자로 맵을 줄 때 맵의 킷값과 일치하는 이름이어야 한다.


3. xml매핑

SQL문xml파일까지 등록이 완료 되었으면, mybatis에서 인식할 수 있도록 매핑작업을 해 주어야 한다.
처음 연결설정 해 두었던 xml파일에서 아래와 같이 SQL문xml파일의 경로를 등록시켜 준다.

<configuration>
   . . .
    <mappers>
        <mapper resource="/mappers/show-mapper.xml" />
    </mappers>
</configuration>


◆ SQL 사용

SqlSession sql = factory.openSession();
위 mybatis준비 과정에서 생성시킨 Sqlsession객체를 이용하여 모든 sql문을 실행한다.


▶ 사용하고자 하는 sql문에 따라 메서드가 다르다.

  • sql.insert() :
  • sql.update() :
  • sql.delete() :
  • sql.selectOne() :
  • sql.selectList() :


▶ SQL문 실행 방법

xml에 등록한 sql문을 사용하기 위해 <mapper>태그의 namespace옵션과 sql태그의 id를 식별자 인자로 사용한다.
ex) sql.selectOne("namespace명.sql태그id");

<mapper namespace="show">
	<select id="readOne" parameterType="java.lang.String"
		resultType="java.util.HashMap">
		select * from member
	</select>
</mapper>
//  처럼 매핑 작업을 하였다면, 해당 SQL문을 호출할 때는 아래와 같이 사용한다.

sql.insert(show.readAll);


  • 두 번째 인자로는 SQL문의 파라미터

    값에 해당하는 값을 넣어준다. 파라미터가 없을 경우 넣지 않으면 된다. (조건은 디폴트 오브젝트 형으로 들어간다. )

    파라미터를 하나만 받는 경우에는 해당 값을 인자로 바로 넘겨주면 되지만, 파라미터가 여러 개일 경우 map을 이용해서 넣게 되고, map일 경우 xml파일에서 설정한 변수명(ex) #{변수})과 map의 킷값이 일치해야 한다.

  • selectOne()
    select문의 결과가 하나밖에 없을 때만 사용하는 메서드 없으면 null을 반환. (결과가 여러개일 경우 오류)
  • selectList()
    select문의 결과가 여러 개일 때 사용하는 메서드로 resultType으로 설정했던 타입을 제네릭으로 하는 List객체를 반환받는다.
    ex ) List<resultType>
  • 파라미터 값으로 null이 들어가는 값을 넣을 수 없다.
  • 보통 select문의 결과로 여러 개의 컬럼일 때는 resultType으로 map형태로 받아오게 된다.
    (키를 컬럼명으로하는 Map)
  • map으로 받아올 때 키의 값은 컬럼 대문자로 설정하여 불러오게 된다. 따라서 호출할 때 map.get(“NO”)의 형식으로 대문자를 인자로 불러온다.


▶ DB데이터 타입에 따른 변환

오라클 데이터베이스의 데이터타입에 따른 Java의 데이터타입 변환은 아래와 같이 이루어진다.

  • VARCHAR2 = String
  • DATE = Date
  • NUMBER = BigDecimal


▶ BigDecimal객체

BigDecimal타입은 integer, double, long… 등의 숫자 객체를 담당하는 java.Math 소속의 객체로 원하는 타입으로 변환해서 사용할 수 있다.

new BigDecimal(213123);
new BigDecimal(123.213);
=>
new BigDecimal.intValue() 또는 doubleValue() 등으로 변환해서 사용이 가능하다.


◆ VO객체를 이용 myBatis

VO(ValueObject)는 데이터를 담을 저장용 객체를 의미하며(직접 만드는 객체), 기존 Map등의 객체로 받던 SQL반환 객체를 VO객체를 통해 받을 수 있다.


1. 객체 클래스 만들기

DB작업의 인자로 넣을 멤버 변수를 설계하고 설계한 멤버 변수에 해당하는 getter와 setter메서드를 추가하여 객체를 만든다. ( 기본 생성자는 필수 )

getter와 setter는 (ctrl+shift+s)단축키로 이클립스에서 지원하는 기능으로 빠르게 생성이 가능하다.


2. 태그 매핑

SQL문을 등록하는 xml파일의 <mapper> 태그안에 <resultMap>태그를 이용하여 VO객체를 아래와 같이 등록한다.

<resultMap type="vos.PlaceVo" id="place">
    <result column="r" property="r" />
    <result column="c" property="c" />
    <result column="no" property="no" />
</resultMap>
<select id="readtwo" resultMap="place"> 
    select * from place where no=#{no}
</select>


<resultMap>

사용할 VO객체를 정의하고 매핑 시킬 id를 설정하는 태그

  • type

    : 사용할 VO객체의 경로

  • id

    : sql문 태그의 resultMap의 값으로 사용할 id

<result>
  • column

    : DB의 컬럼명

  • property

    : DB컬럼과 매칭 시킬 VO객체의 멤버 변수명
    ex ) <result colum=“no” property = “number” />
    DB테이블의 no컬럼명은 VO객체의 number멤버변수와 매칭된다.

▶ <select> 태그의 resultMap옵션

기존의 Map객체와 같은 기본 객체들은 resultType이라는 옵션으로 사용하였지만, VO객체를 반환형으로 사용하려면 resultMap을 옵션으로 사용하여야 하고, resultMap의 값으로 <resultMap>태그의 id를 입력한다.


▶ resultMap을 사용하는 이유?

VO객체를 꼭 resultMap으로 사용해야 하는것은 아니다. resultType에서도 멤버 변수명과 DB컬럼명이 같다면 VO객체를 사용할 수 있다.
하지만, DB와 JAVA의 변수명 규칙이 달라 객체의 멤버 변수명과 DB컬럼명이 다를 경우 resultMap으로 매핑작업을 해 주어야 한다.

Oracle의 복합단어의 경우 단어의 구분을 언더바(_)를 사용하지만, JAVA의 경우 CAMEL규칙에 따라 복합 단어의 구분을 복합단어 첫문자 대문자로 표시하기 때문에 DB컬럼명과 멤버변수명이 달라질 수 있다.

  • DB : ex) phone_no
  • JAVA : ex) phoneNo


◆ <resultMap>을 활용한 1:N 데이터 불러오기

resultMap을 정의 할 때 <collection>태그를 통해 다른 쿼리의 결과값을 하나의 변수에 포함시킬 수 있다
즉 하나의 행 데이터에서 하나의 컬럼 변수가 쿼리 리스트로 세팅되는 형태

<resultMap id="prd_banner" type="CmResMap">
    <id		property="V_SITECD"	column="V_SITECD" />
    <id		property="V_LANGCD"	column="V_LANGCD"/>
    <result property="V_REC_TYPENM" 	column="V_REC_TYPENM"/>
    <result property="N_SORT"         	column="N_SORT"/>
    <collection property="banner_list" ofType="CmResMap"
                column="{   i_sLangcd=V_LANGCD
                            ,i_sSitecd=V_SITECD
                        }"
                select="ShopDao.getShopProductTagList"/>
</resultMap>

=> resultMap속성을 prd_banner로 하는 쿼리문은 위 <resultMap>형태로 반환되기 때문에 <collection>태그의 propertiy속성인 banner_list라는 변수에 select속성인 ShopDao.getShopProductTagList쿼리 리스트가 담기게 된다.

  • <collection>태그의 select쿼리의 동적 변수는 column컬럼의 값을 사용한다.


◆ insert 작업

insert / update / delete은 데이터를 불러오는 작업이 아니기 때문에 resultType 또는 resultMap을 설정할 수 없다. ( select에서는 resultType 또는 resultMap은 필수 )


1. 매핑

파라미터가 필요할 경우 parameterType을 설정하여 해당 파라미터 타입에 맞는 파라미터를 넘겨줄 수 있다.

<insert id="addOneMap" parameterType="hashmap">
    insert into place values(#{no},#{r},#{c})
</insert>
<insert id="addOneVo" parameterType="vos.Placevo">
    insert into place values(#{no},#{r},#{c})
</insert>


2. 작업

Map map = new HashMap();
map.put("no", 5);
map.put("r", 6);
map.put("c", 7);
try {
    int r = sql.insert("place.addOneMap", map);
} finally {
    sql.close();
}
  • 인자가 여러 개일 경우 컬렉션 계열로 넣어주어야 한다.
    ( 단, 맵일때는 #{no} 등의 인자로 넣은 변수명이 맵의 키 값과 일치해야 하고, 사용자가 만든 VO객체의 경우 멤버변수와 일치하는 값으로 설정해야 한다. )
  • sql작업을 할 때 try~ finally로 묶어서 close를 무조건 해주어야 한다.
  • 조건문에서 < 나 > 를 쓸때는 태그로 인식할 수 있기 때문에 &lt (< ), &gt ( > )로 쓰면된다.
  • 기본적으로 마이바티스의 파라미터로는 null값을 가지고 있는 변수 값을 넣을 수 없다.
    ( Map이 null이 아닐지라도, Map안의 value값이 null일 경우 불가능 )


▶ null값을 허용하는 방법

마이바티스에서는 null값으로 셋팅이 불가능하기 때문에 null값이 필요할 때는 sql문을 따로 설정해야 하지만, 컬럼 타입에 jdbcType을 지정해주면 null value도 셋팅이 가능하게 된다.

  • jdbcType : VARCHAR, NUMERIC, DATE
    ex ) #{max, jdbcType=NUMERIC}