다잇소


[IT/트랜드] [다it소]Java Annotation 이해하기 – ⑤ Annotation을 이용한 IBatis 개발

2016.03.01

보경샘_java_다잇소



Java Annotation 이해하기 – ⑤ Annotation을 이용한 IBatis 개발


 

1. 환경설정


IBatisPersistence Framework로써 우리나라에서 널리 쓰여지고 있어서, 이미 많은 분들이 사용법이나 환경 설정을 알고 있을 것 입니다. 하지만, 환기도 시킬 겸 환경설정에 대해서 이야기하고, 기존의 Annotation없이 사용할 경우와 있을 경우의 사용법이 어떻게 다른지 알아 보겠습니다. IBatis2.X버전에서 3.X버전으로 판올림하면서, MyBatis라는 이름으로 변경 했습니다. 대부분의 IBatis 프로젝트 참여자들의 현재 MyBatis에 참여 중이며, 둘 사이에 몇 가지 차이점이 있지만 IBatis의 판올림 버전으로 봐도 무방하겠습니다


환경설정 만큼 재미없고 까다로운 부분이 있을까요? 설명이 잘 되어 있어도, 어느 부분이 핵심인지 한 부분 한 부분 놓치지 않고 잘 따라가야 하기 때문인 것 같네요. 요즘 편한 GUI환경에서 개발을 하다 보니, 너무 익숙해 지지 않았나 하는 생각도 듭니다. 이번에 구성하려는 환경은 웹 환경이 아니라, 독립환경이니 Tomcat 같은 Java WAS는 별도로 필요하지 않습니다. 기본적인 설정환경은 Eclipse Luna Java EE IDE for Web Developers 버전입니다.


1. 사전준비


항상 설치를 하려면 우리가 필요한 파일들을 다운로드 받아야 합니다.


MariaDB JDBC client : mariadb-java-client-1.3.5.jar –


http://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client/1.3.5


Mysql JDBC가 아닌 MariaDB로 변경하였습니다.


MyBatis 3.3.0 : MyBatis-3.3.0.jar –


http://mvnrepository.com/artifact/org.MyBatis/MyBatis/3.3.0


여기서는 하단에 보면 Compile Dependencies 라는 부분이 있는데, slf4j-api-1.7.14.jar, slf4j-log4j12-1.7.14.jar,log4j-1.2.17.jar 파일을 LOG설정을 위해 같이 다운로드 받으시기 바랍니다.


ORDER 테이블의 변경


– RENAME TABLE `order ` TO `order_lst`;


ALTER TABLE `order_lst` CHANGE COLUMN `ORDER_CNT1` `ORDER_CNT` SMALLINT(6) NOT NULL COMMENT 상품개수 AFTER `CUSTOM_ID`;


Table명을 ORDER에서 ORDER_LST로 변경하고, PRODUCT_CNTORDER_CNT로 변경을 합니다.,


2. 환경설정


프로젝트 생성 : MyBatis라는 Java프로젝트를 생성을 합니다. 다음 사이트를 참조하여 생성하기 바랍니다.


Java 프로젝트 생성


필수 jar library에 포함 : Eclipse에서 lib폴더를 생성 후 mariadb-java-client-1.3.5.jar, MyBatis-3.3.0.jar ,slf4j-api-1.7.14.jar, slf4j-log4j12-1.7.14.jar,log4j-1.2.17.jar에 복사하여 넣습니다. 그리고, 난 후 jar파일을 선택하고 Build Path > add build path를 선택하여 library에 추가합니다.


외부 jarlib에 추가 할 수 데, 자세한 설명은 다음을 사이트를 참조하여 바랍니다.


Jar Library추가 방법


log4j.properties작성 : 기본적으로 생성되어 있는 src폴더에 log4j.properties를 생성한 다음, 다음 내용을 작성합니다.










log4j.rootLogger=DEBUG, stdout


log4j.appender.stdout=org.apache.log4j.ConsoleAppender


log4j.appender.stdout.layout=org.apache.log4j.PatternLayout


log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %c %m%n

mybatis-config.xml작성 : 기본적으로 생성되어 있는 src폴더에 Configuration 작성을 다음과 같이 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>


<environments default=“development”>


<environment id=“development”>


<transactionManager type=“JDBC” />


<dataSource type=“UNPOOLED”>


<property name=“driver” value=“org.mariadb.jdbc.Driver”


<property name=“url” value=“jdbc:mysql://localhost:3306/shoppingmall” />


<property name=“username” value=“malladmin” />


<property name=“password” value=“123456” />


</dataSource>


</environment>


</environments>


<mappers>


<mapper resource=“person/bk/MyBatis/mapper/MyTestMapper.xml” />


</mappers>


</configuration>


 

IBatis와 다른 점은 우선 눈에 뛰는 것은 기존에 sqlMapConfigconfiguration 요소로 바뀌고, sqlMap대신에 mappersmapper로 바뀐 것을 알 수 있습니다.


transactionManager에는 type 속성에 JDBCMANAGED가 있는데, 독립실행인 경우는 일반적으로 JDBC로 자체관리하고, EJBMiddle웨어 자체관리가 있는 경우는 MANAGED가 적당합니다. dataSourcetype 속성에는 UNPOOLED, POOLED, JNDI가 있습니다. 여기서는 독립적으로 실행하고, 바로 종료되니 UNPOOLED를 선택하였습니다. 우선 SampleMyTestMapper.xml를 하나 추가하여 간단한 조회를 해 보도록 하겠습니다.


3. 예제 프로그램 실행


Mapper설정 mybatis-config.xml에 추가합니다. 중요한 사실은 Mapper파일을 생성하는 위치는 정확히 같은 경로에 위치해야 되므로, package person.bk.mybatis.mapper라는 생성 후에 해당 package아래에 MyTestMapper.xml를 작성을 합니다.


MyTestMapper.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=“person.bk.mybatis.mapper.MyTestMapper”>


<select id=“findAllCustoms” resultType=“map”>


SELECT custom_id, custom_name , addr


FROM CUSTOM


ORDER BY custom_id


</select>


</mapper>

여기서 중요한 사실은 sqlMap에서는 namespace가 필수는 아니었지만, 여기서는 mapper에서는 namespace가 필수입니다. select요소를 하나만들고 idfindAllCustoms라고 설정하였습니다.


다음은 환경설정 내용을 SqlSessionFactory을 작성을 위해 person.bk.mybatis.examMyBatisSqlSessionFactory.java를 작성합니다.










package person.bk.mybatis.exam;


import java.io.IOException;


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 MyBatisSqlSessionFactory {


private static SqlSessionFactory sqlSessionFactory;


public static SqlSessionFactory getSqlSessionFactory() {


if (sqlSessionFactory == null) {


InputStream inputStream;


try {


inputStream = Resources.getResourceAsStream(“mybatis-config.xml”); // 환경파일은 CLASSPATH내에 위치해야 함


sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


} catch (IOException e) {


throw new RuntimeException(e.getCause());


}


}


return sqlSessionFactory;


}


public static SqlSession openSession() {


return getSqlSessionFactory().openSession();


}


}

다음 Session를 열고 select를 실행하는 MyTest.java 파일을 작성하겠습니다.










package person.bk.mybatis.exam;


import java.util.List;


import java.util.Map;


import org.apache.IBatis.session.SqlSession;


import org.slf4j.Logger;


import org.slf4j.LoggerFactory;


public class MyTest {


public static void main(String[] args) {


Logger logger = LoggerFactory.getLogger(“DEBUG”);


SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();


try {


List<Map<String, Object>> list = sqlSession.selectList(“person.bk.mybatis.mapper.MyTestMapper.findAllCustoms”);


for( Map<String, Object> map : list ) {


logger.debug(map.toString());


}


} finally {


sqlSession.close();


}


}


}



실행을 하면 다음과 같은 결과를 볼 수 있습니다. 데이터는 미리 입력하여 주시기 바랍니다.










2016-03-01 09:02:06,034 [DEBUG] person.bk.mybatis.mapper.MyTestMapper.findAllCustoms – ==> Preparing: SELECT custom_id, custom_name , addr FROM CUSTOM ORDER BY custom_id


2016-03-01 09:02:06,130 [DEBUG] person.bk.mybatis.mapper.MyTestMapper.findAllCustoms – ==> Parameters:


2016-03-01 09:02:06,218 [DEBUG] person.bk.mybatis.mapper.MyTestMapper.findAllCustoms – <== Total: 4


2016-03-01 09:02:06,239 [DEBUG] DEBUG – {custom_name=홍길동, custom_id=2016000001, addr=80000||대한민국||서울시||강서구}


2016-03-01 09:02:06,239 [DEBUG] DEBUG – {custom_name=임걱정, custom_id=2016000002, addr=70000||대한민국||경기도||광명시}


2016-03-01 09:02:06,240 [DEBUG] DEBUG – {custom_name=손오공, custom_id=2016000003, addr=90000||중국|| 후난성|| 건천동}


2016-03-01 09:02:06,240 [DEBUG] DEBUG – {custom_name=강감찬, custom_id=2016000004, addr=11000||대한민국|| 경기|| 고양시}

여기까지 되면 무사히 환경 설정을 마치고, 본격적으로 Annotation을 이용한 MyBatis를 실제 구현할 시간입니다.


2. Mapped SQLXML


이 방법은 현재 IBatis에서 사용하는 방법과 크게 차이 없으나, 기존에 사용되지 않았던 개념인 Mapper라는 Interface를 활용하게 됩니다. Mapper사용함으로써 기존에 형에 불일치와 같은 잠재적인 오류를 없앨 수 가 있습니다. 그렇지만, 역시 하나의 번거로운 단순작업이 추가되므로, 개발 시에는 유용하다고 말하기 힘들 것 같습니다. 그러나, Mapper InterfaceAnnotation를 사용하게 되면 아주 유용한 Interface로 바뀌게 됩니다. 우선 간단하게 CustomerMapper.xmlperson.bk.mybatis.mapper 패키지 안에 작성하겠습니다. 누누히 강조하지만 , 경로가 제대로 맞지 않으면 동작하지 않으니, 항상 어디에 무엇을 두는지 잘 읽고 따라 하셔야 합니다.


우선 Mappermybatis-config.xmlmappers에 다음 mapper요소를 추가합니다.
<mapper resource=”person/bk/mybatis/mapper/CustomMapper.xml” />


CustomMapper 파일을 다음과 같이 작성합니다.










<?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=“person.bk.mybatis.mapper.CustomMapper”>


<resultMap type=“person.bk.mybatis.exam.Custom” id=“CustomResult”>


<id property=“customId” column=“custom_id” />


<result property=“customName” column=“custom_name” />


<result property=“addr” column=“addr” />


</resultMap>


<select id=“findAllCustoms” resultMap=“CustomResult”>


SELECT custom_id AS customId, custom_name AS customName, addr AS addr


FROM CUSTOM


</select>


<select id=“findCustomById” parameterType=“String” resultMap=“CustomResult”>


SELECT custom_id , custom_name , addr


FROM CUSTOM


WHERE custom_id=#{customId}


</select>


<insert id=“insertCustom” parameterType=“person.bk.mybatis.exam.Custom”>


INSERT INTO custom(


custom_id,custom_name,addr


)


VALUES (


#{customId}, #{customName},#{addr}


)


</insert>


<update id=“updateCustom” parameterType=“person.bk.mybatis.exam.Custom”>


UPDATE custom


SET addr = #{addr}


WHERE custom_id=#{customId}


</update>


<delete id=“deleteCustom” parameterType=“String”>


DELETE FROM custom WHERE custom_id=#{customId}


</delete>


</mapper>


 

여기서 또 하나 중요한 사실은 MyBatis에서는 Mapper라는 interface를 사용하여 형일치 문제에 대한 오류를 미리 방지 할 수 있다는 것입니다. 별다른 찾는 프로그램이 없다면 Mapper interface는 반드시 Mapper.xml과 같은 경로에 있어야 합니다.


person.bk.mybatis.mapper 패키지에 다음과 같이 CustomMapperinterface를 작성을 합니다.










package person.bk.mybatis.mapper;


import java.util.List;


import person.bk.mybatis.exam.Custom;


public interface CustomMapper {


List<Custom> findAllCustoms();


Custom findCustomById(String customId);


void insertCustom(Custom custom);


void updateCustom(Custom custom);


void deleteCustom(String customId);


}



여기서 보면 Mapper.xmlsql에 해당하는 id와 같은 이름의 method를 만들고, 해당 형에 맞는 parameter들이 설정된 것을 볼수 있습니다. 반드시 일치시켜야 되는 것입니다.


다음은 실제 실행을 위하여, Custom, CustomServiceCustomServiceTest를 각각 person.bk.mybatis.exam 아래와 같이 작성하겠습니다.


Custom.java










package person.bk.mybatis.exam;


import java.lang.reflect.Method;


public class Custom {


private String customId;


private String customName;


public String getCustomName() {


return customName;


}


public void setCustomName(String customName) {


this.customName = customName;


}


private String addr;


public String getCustomId() {


return customId;


}


public void setCustomId(String customId) {


this.customId = customId;


}


public String getAddr() {


return addr;


}


public void setAddr(String addr) {


this.addr = addr;


}


@Override


public String toString() {


StringBuilder builder = new StringBuilder();


Class c = this.getClass();


Method[] methods = c.getDeclaredMethods();


for (Method method : methods) {


if(method.getName().startsWith(“get”)){


try {


builder.append(method.getName()).append(” -> “).append(method.invoke(this, null)).append(‘\n’);


} catch (Exception e) {


e.printStackTrace();


}


}


}


return builder.toString();


}


}


 

CustomService.java










package person.bk.mybatis.exam;


import java.util.List;


import org.apache.ibatis.session.SqlSession;


import org.slf4j.Logger;


import org.slf4j.LoggerFactory;


import person.bk.mybatis.mapper.CustomMapper;


public class CustomService {


private Logger logger = LoggerFactory.getLogger(getClass());


public List<Custom> findAllCustoms() {


SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();


try {


CustomMapper customMapper = sqlSession.getMapper(CustomMapper.class);


return customMapper.findAllCustoms();


} finally {


sqlSession.close();


}


}


public Custom findCustomById(String customId) {


logger.debug(“Select Custom By ID :{}”, customId);


SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();


try {


CustomMapper customMapper = sqlSession.getMapper(CustomMapper.class);


return customMapper.findCustomById(customId);


} finally {


sqlSession.close();


}


}


public void insertCustom(Custom Custom) {


SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();


try {


CustomMapper customMapper = sqlSession.getMapper(CustomMapper.class);


customMapper.insertCustom(Custom);


sqlSession.commit();


} finally {


sqlSession.close();


}


}


public void updateCustom(Custom Custom) {


SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();


try {


CustomMapper customMapper = sqlSession.getMapper(CustomMapper.class);


customMapper.updateCustom(Custom);


sqlSession.commit();


} finally {


sqlSession.close();


}


}


public void deleteCustom(String customId) {


SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();


try {


CustomMapper customMapper = sqlSession.getMapper(CustomMapper.class);


customMapper.deleteCustom(customId);


sqlSession.commit();


} finally {


sqlSession.close();


}


}


}

CustomServiceTest.java










package person.bk.mybatis.exam;


import java.util.List;


import org.junit.AfterClass;


import org.junit.Assert;


import org.junit.BeforeClass;


import org.junit.Test;


import org.slf4j.Logger;


import org.slf4j.LoggerFactory;


public class CustomServiceTest {


Logger logger = LoggerFactory.getLogger(“DEBUG”);


private static CustomService customService;


@BeforeClass


public static void setup() {


customService = new CustomService();


}


@AfterClass


public static void teardown() {


customService = null;


}


@Test


public void testFindAllCustoms() {


List<Custom> customs = customService.findAllCustoms();


Assert.assertNotNull(customs);


for (Custom custom : customs) {


logger.debug(custom.toString());


}


}


@Test


public void testFindCustomById() {


Custom custom = customService.findCustomById( “2016000004”);


Assert.assertNotNull(custom);


logger.debug(custom.toString());


}


@Test


public void testInsertCustom() {


Custom custom = new Custom();


custom.setCustomId(“2016000005”);


custom.setCustomName(연개소문);


custom.setAddr(“12000||대한민국||경기||수원시);


customService.insertCustom(custom);


}


@Test


public void testUpdateCustom() {


Custom custom = new Custom();


custom.setCustomId(“2016000005”);


custom.setAddr(“13000||대한민국||경기|| 오산시);


customService.updateCustom(custom);


}


@Test


public void testDeleteCustom() {


customService.deleteCustom(“2016000005”);


}


}



CustomServiceTest.java에서 테스트는 JUnitTest를 사용하였는데, 실행 시에 JUnit Test는 볼 수가 있습니다. 일반적인 main method는 사용하는 것보다 더 간단하게 테스트 해 보실 수 있습니다.


너무 길어지는 관계로 다음 시간에는 이 부분을 Annotation으로 변경하겠습니다.


읽어 주셔서 감사합니다.

설정된 프로필 사진이 없습니다.
| Wise리더
관심분야 IT,여행,맛집

카테고리 레이어 닫기