Mybatis 설정 및 예제 만들어보기

2022. 9. 2. 19:36프로그래밍/데이터베이스

728x90

이 문서의 목적은 mybatis를 사용해서 여러개의 테이블에서 데이터를 가져와서 결과 값을 조합 하여 최종 데이터를 만들어 보기 위해서 시작 한 것입니다.


그리고 mybatis 가 정형화 잘 되어 있긴 해도 기억을 더듬거리면서 따라가려면 또 한 참을 헤매고 있어서, 정형화 된 순서를 한 번 만들어 봐야 하겠다고 생각한 점도 있습니다.

예전에 한 번 ibatis 설정에 대한 내용을 올리기는 했습니다.

 

오라클연결- 10g

다음은 오라클 10g를 중심으로 iBatisNet에서 오라클 접속하고 질의 하는 방법을 설명합니다. 목차 1. D...

blog.naver.com

 

지금은 mybatis 이네요~
my batis  내용에 대해서도 올렸는 데...

 

MyBatis 자습 – CRUD 조작과 관계 매핑 – Part 1

CRUD 조작 MyBatis는 JDBC를 직접 사용하는 것과 비교 비교 할 수 없을 정도로 #데이터베이스 #...

blog.naver.com

 

 좀 부족 한 것 같아서 다시 진행 해보기로 했습니다.

 

0. mybatis 다운로드 받기 

다운로드를 받아야 겠죠...3.5.10 다운을 받았습니다.

 

https://github.com/mybatis/mybatis-3/releases

1. 연습 프로그램 만들기

사실, 공식 사이트를 잘 읽어보고 연습하면 젤 좋은 데 성격도 급하고 많은 사람들이 자신만의 길을 잘 가고 있기 때문에 그 중에 몇 개를 골라서 시작 해보면 어떨까 하는 게 저의 생각입니다.

하지만, 어떤 것이 바른 길인지는 아래 사이트에서 확인은 해봐야 겠죠...


https://mybatis.org/mybatis-3/ko/getting-started.html

연습 프로그램을 만들기 위해서 참고 문서[1]에서 DBUtil 을 가지고 와서, 연결을 시킬 것입니다.

그리고 난 다음 참고 문서[4]를 스택오버플로우 글을 번역 해 보면



질문>


GWT에서 iBatis를 사용 하려고 합니다.
테이블은 Airport, Terminals 그리고 Flights 이 데이터베이스에 존재 하고 있는 시나리오 입니다.

Airport 는 다양한 터미널들을 가질 수 있으며, 터미널은 하나의 비행장과 여러대의 비행기를 수용 할 수 있습니다.
그리고 비행기는 하나의 터미널 안에 있겠죠. 그래서 테이블 구조는 아래처럼 만들었습니다.

Airport 
 -id 
 -name 
 -terminal_id

Terminals 
 -id 
 -name 
 -flight_id

Flights 
 -id 
 -airline
 -terminal_id


select 구문은 다음과 같이 실행 했습니다.

SELECT airport.name AS Airport,
       terminals.name AS Terminal,
       flights.airline,
FROM airport,
     terminals,
     flights
WHERE airport.terminal_id = terminals.id
  AND terminals.flight_id = flights.id;

위 질의문의 결과물을 가지는 결과에 대한 sql 매핑은 어떻게 해야 할까요?

3개 테이블에서 각각에서 만들어지는 모델 객체의 결과를 저장하는 것이 아니고, 결과 집합이 여러개 테이블에서 가져 오는 것이라 많이 헷갈립니다.


대답:


결과에 맞도록 커스텀 밸류 오브젝트(VO)를 생성 하면 됩니다.

<sqlMap namespace="Arrival">
<resultMap id="Arrival" class="com.flight.vo.Arrival">
    <result property="airport" column="Airport" />
    <result property="terminal" column="Terminal" />
    <result property="airline" column="airline"/>
</resultMap>

<select id="retrieveAllArrivals" resultMap="Arrival.Arrival" >
    select airport.name as Airport, terminals.name as Terminal, flights.airline
    FROM airport, terminals, flights 
    WHERE airport.terminal_id = terminals.id 
    AND terminals.flight_id = flights.id
</select>
</sqlMap>




위의 문서를 확인 해 보았으니 그냥 따라 하면 될 것 같습니다.

한 가지 제약 사항이라면, 만약 회사 내부라면 외부 인터넷을 사용 할 수가 없을 수도 있습니다.

회사 내부라고 생각 하고 진행 합니다.

 

2. 환경설정 파일 만들기 

 

환경 설정 파일은 mybatis-config 라고 이름을 짓고 나서, 해당 mybatis-config.xml 은 소스 폴더인 resources 밑에 sqlMap 폴더에다 생성 하도록 합니다.

<?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>
   <!-- Import external profile -->
   <properties resource="application.properties"/>

   <environments default="development">
       <environment id="development">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <property name="driver" value="${spring.datasource.driver-class-name}"/>
               <property name="url" value="${spring.datasource.url}"/>
               <property name="username" value="${spring.datasource.username}"/>
               <property name="password" value="${spring.datasource.password}"/>
           </dataSource>
       </environment>
   </environments>

   <mappers>
       <!-- To configure Mapper.xl Path to file -->
       <mapper resource="com/sky/demo/dao/AccountMapper.xml" />
       <!-- 
       <package name="com.bluesky.mybatisstudy.dao"/>
       -->
   </mappers>
</configuration>



위의 dtd 파일의 영향 때문인지 이클립스에서 빨간 색 오류가 많이 뜨네요... 그냥 무시 하면 될 것 같습니다.

다만 점검 해야 할 부분은 해당 파일을 UTF-8 아스키 형태의 문서가 되면 좋을 것 같네요

해당 당 dtd 파일을 직접 http://mybatis.org/dtd/mybatis-3-config.dtd 에서 받아서저장 한 다음 해당 dtd 를  mybatis-config.xml  파일과 같은 디렉토리에 복사해 넣고 난 다음, 아래 부분을

 

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


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


로 변경 해 주었습니다.

그리고 application.properties 파일의 형식은 다음과 같습니다.

datasource.driver-class-name=oracle.jdbc.driver.OracleDriver

jdbc.ipaddr=xxx.xxx.xxx.xxx
jdbc.port=1521
jdbc.service=DB1

datasource.url=jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:DB1

datasource.username=user
datasource.password=userpasswd

음, 그리고 제일 중요 한 것은 datasource.url 프로퍼티 입니다.  이 프로퍼티와 

jdbc.ipaddr=xxx.xxx.xxx.xxx
jdbc.port=1521
jdbc.service=DB1

위의 프로퍼티 값들이 datasource.url 프로퍼티 틀리다면, datasource.url 프로퍼티 값을 가져다가 오라클로 바인딩 할 것 입니다.

따라서, datasource.url 프로퍼티 값의 설정이 젤 중요 합니다.

 

2. 매퍼 파일 만들기 

자, 그럼 매퍼 설정을 해 주어야 합니다. 이

솔직히, package 엘리먼트는 뭐 하는 것인지 모르겠습니다. 정확하게는 현재 제가 할려는 일과는 거리가 좀 있어서 그냥 넘기기로 하고

<mappers>
   <!-- To configure Mapper.xl Path to file -->
   <mapper resource="com/sky/demo/dao/AccountMapper.xml" />
   <!-- 
   <package name="com.bluesky.mybatisstudy.dao"/>
   -->
  </mappers>

위에서 사용 하는 CheckDataMapper.xml 파일의 내용을 만들어 보기로 합니다.

앞으로 어떻게 다시 변경 될 지 모르겠으나, 사람들의 사랑을 받고 있는 라이브러리인지라 쉽게 표준을 흔드는 일은 없을 것이라고 봅니다. ibatis  의 형태를 그대로 가져 온 것을 보면 그렇기도 하구요.

CheckDataMapper.xml 파일의 내용을 다음과 같이 작성 하도록 하겠습니다.

<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "mybatis-3-mapper.dtd">

<mapper namespace="com.tobee.biz.v2.check.mapper.ICheckDataMapper">
    <resultMap id="CheckData" type="com.tobee.biz.v2.check.vo.CheckData" >
        <result property="Team" column="TEAM" />
        <result property="Name" column="NM" />
        <result property="TpCod" column="TP_COD" />
        <result property="ChckNm" column="CHCK_NM" />
        <result property="Cod" column="COD" />
        <result property="ChckDt" column="CHCK_DT" />
        <result property="No" column="NO" />
        <result property="OperatorName" column="OPERT_NM" />
        ...
    </resultMap>
	
	<!--<parameterMap id="test_parameterMap" type="com.tobee.biz.v2.check.vo.CheckData" />-->

	<!--- 1) CheckData -->
	<select id="retrieveCheckData" parameterType="java.util.Map" resultMap="CheckData">
		SELECT 
        	A.COD,
		    A.NO,
		    TO_DATE (A.CHCK_DT, 'YYYY/MM/DD'),
		    DECODE (
		    	(SELECT USR_NM
		        	FROM USR
					WHERE COD = #{Cod} AND EMPNO = CHCK_NM),
				NULL, 
                CHCK_NM,
		        (SELECT USR_NM
		        	FROM CMM_USR
					WHERE CMP_COD = #{cmpCod} AND EMPNO = EXCV_PBCO_CHCK_1_CMPTNR_NM)
			)
		    AS CHCK_NM,      
		    TP_COD,
		    (SELECT 
		    	COD_NM
			FROM 
		    	CMM_COD_DETL
			WHERE 
				COD = #{Cod}
		        AND COD_ID = ID) 
		       AS OPERT_NM
		FROM 
		  	CHCK_RSLT A, 
		  	CHCK_RSLT_IEM B
		WHERE 
			A.COD = B.COD
			AND A.COD = #{Cod}
		    AND A.NO = B.NO
		    AND A.CHCK_DT BETWEEN #{dateStart,jdbcType=VARCHAR} AND #{dateEnd,jdbcType=VARCHAR}
		    AND A.SE_COD = B.SE_COD
		    AND B.RSLT_COD <![CDATA[ <> ]]>'2000'
	</select>
</mapper>

parameterMap 을 사용해보려고 했으나, deprecated  된 내용이라고 하기에 그냥 주석 처리 하였고, 맵 형태로 받아 오는 것으로 변경 했습니다.

 

3. VO 클래스 만들기 

위의 질의문을 그냥 Map 으로 받아 온다면, 데이터베이스 컬럼 명의 경우에는 보통 대문자로 쓰기 때문에 getter/setter 값의 모양이 예뻐보이지 않겠죠?

예를 들자면, VO 클래스인 CheckData 에 다음과 같이 똑같이 컬럼 이름을 선언 한 경우, 아래 처럼 만들 수 있을 것입니다. 

package com.tobee.biz.v2.selfcheck.vo;

import java.io.Serializable;

public class CheckData implements Serializable {
	private static final long serialVersionUID = 292424167983715579L;
	
	private String cmpCod;
	private String dateStart;
	private String dateEnd;
	
	...
	private String TEAM;
	private String NM;
	
	public String getCod() {
		return cmpCod;
	}

	public void setCod(String cod) {
		this.cod = cod;
	}

	public String getDateStart() {
		return dateStart;
	}

	public void setDateStart(String dateStart) {
		this.dateStart = dateStart;
	}

	public String getDateEnd() {
		return dateEnd;
	}

	public void setDateEnd(String dateEnd) {
		this.dateEnd = dateEnd;
	}
...
	public String getTEAM() {
		return TEAM;
	}

	public void setTEAM(String tEAM) {
		TEAM = tEAM;
	}

	public String getNM() {
		return NM;
	}

	public void setNM(String nM) {
		NM = nM;
	}

}

따라서 컬럼이름을 입맛대로 바꾸고 싶다면 resultMap 을 사용해 보는 것도 나쁘지 않을 것 같습니다.

그리고 프로그램 구현 부분에 있는 변수 명과의 투명성 및 일관성을 위해서 많은 고민이 있어야 하겠지만요.

 

그래서, resultMap 도 한번 다음과 같이 만들어 보았습니다.

<resultMap id="CheckData" type="com.tobee.biz.v2.check.vo.CheckData" >
    <result property="TpCod" column="TP_COD" />
    <result property="ChckNm" column="CHCK_NM" />
	<result property="Cod" column="COD" />
    <result property="ChckDt" column="CHCK_DT" />
    <result property="No" column="NO" />
    <result property="OperatorName" column="OPERT_NM" />
</resultMap>

위의 resultMap 은 아래 질의문과 상관이 있겠습니다.

SELECT 
    A.COD,
    A.NO,
    TO_DATE (A.CHCK_DT, 'YYYY/MM/DD'),
    DECODE (
        (SELECT USR_NM
            FROM USR
            WHERE COD = #{Cod} AND EMPNO = CHCK_NM),
        NULL, 
        CHCK_NM,
        (SELECT USR_NM
            FROM CMM_USR
            WHERE CMP_COD = #{cmpCod} AND EMPNO = EXCV_PBCO_CHCK_1_CMPTNR_NM)
    )
    AS CHCK_NM,      
    TP_COD,
    (SELECT 
        COD_NM
    FROM 
        CMM_COD_DETL
    WHERE 
        COD = #{Cod}
        AND COD_ID = ID) 
       AS OPERT_NM

 

그럼 위의 클래스는 다음과 같이 바뀌어야 겠죠?

package com.tobee.biz.v2.selfcheck.vo;

import java.io.Serializable;

public class CheckData implements Serializable {
	
	...
    private String team;
    private String name;
    private String CheckData;
    
    private String TpCod;
    private String ChckNm;
    private String Cod;
    private String ChckDt;
    private String No;
    private String OperatorName;

	...
    public String getOperatorName() {
        return OperatorName;
    }

    public void setTeam(String OperatorName) {
        this.OperatorName = OperatorName;
    }

    public String getCheckData() {
        return CheckData;
    }

    public void setTeam(String CheckData) {
        this.CheckData = CheckData;
    }

    public String getTpCod() {
        return TpCod;
    }

    public void setTeam(String TpCod) {
        this.TpCod = TpCod;
    }

    ...

    public String getTeam() {
        return team;
    }

    public void setTeam(String team) {
        this.team = team;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

4. 매퍼 클래스 만들기 

그럼 위에서 정의한 매퍼 파일의 내용 중 어떤 동작을 사용 할 것인지에 대해서 정의 해주는 매퍼 클래스를 만들어 보도록 하겠습니다.

package com.tobee.biz.v2.check.mapper;

import java.util.List;
import java.util.Map;

import com.tobee.biz.v2.check.vo.CheckData;

public interface ICheckDataMapper {
	
	/**
	 * 1) CheckData 
	 * 가져올거예요 CheckData
	 * @param paramMap 
	 * @return
	 */
	public List<CheckData> retrieveCheckData(Map<String,String> paramMap);
}

위의 코드의 내용은 의미 적으로 아래 CheckDataMapper.xml 파일에서 가져와서 본을 뜬 것입니다.

그리고 인터페이스 선언 만으로 가능 하도록 잘 만들어져 있습니다. 대신, CheckDataMapper.xml 파일과 연관성을 잘 생각하고 작성 해야 한다는 것을 잊으면 안 됩니다.

 

<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "mybatis-3-mapper.dtd">

<mapper namespace="com.tobee.biz.v2.check.mapper.ICheckDataMapper">
    ...
    
	<select id="retrieveCheckData" parameterType="java.util.Map" resultMap="CheckData">
		...
	</select>
</mapper>

 

5. 서비스 클래스 만들기 


그럼 외부에서 이 데이터를 조작 하기 위해서 인터페이스 처럼 열어 주어야 할 서비스 클래스를 만들 면 될 것입니다. 

package com.tobee.biz.v2.selfcheck.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.tobee.biz.v2.selfcheck.mapper.ICheckDataMapper;
import com.tobee.biz.v2.selfcheck.vo.CheckData;
import com.tobee.biz_v2.DBUtil;

public class SelfCheckService {
	// obtain SqlSession object 
    private ISelfCheckMapper selfChkMapper= DBUtil.openSession().getMapper(ISelfCheckMapper.class);
  
	
	/**
	 * 1) CheckData 
	 * 가져올거예요 CheckData
	 * @param paramMap 
	 * @return
	 */
	public List<CheckData> retrieveCheckData(Map<String,String> paramMap)
	{
        Map<String, String> paramMap = new HashMap<String,String>();
        paramMap.put("Cod", Cod);
        paramMap.put("dateStart", dateStart);
        paramMap.put("dateEnd", dateEnd);
        return selfChkMapper.retrieveMissingCalibration(paramMap);
	}
	
}

위의 코드도 마찬가지로 아래 파일과 관련이 당연히 있겠죠?

WHERE 
    A.COD = B.COD
    AND A.COD = #{Cod}
    AND A.NO = B.NO
    AND A.CHCK_DT BETWEEN #{dateStart,jdbcType=VARCHAR} AND #{dateEnd,jdbcType=VARCHAR}
    AND A.SE_COD = B.SE_COD
    AND B.RSLT_COD <![CDATA[ <> ]]>'2000'

 

6. 메인 클래스 만들기 

마지막으로 메인 클래스를 하나 만들어 주면서 끝내겠습니다.

package com.tobee.biz.v2.main;

import java.util.Iterator;
import java.util.List;

import com.tobee.biz.v2.selfcheck.service.SelfCheckService;
import com.tobee.biz.v2.selfcheck.vo.SelfCheck;

public class BizMain {
	public static void main(String[] args)
	{
		SelfCheckService selfChkService = new SelfCheckService();
		
		final String Cod = "TobeeCode1234";
		final String dateStart = "20220801";
		final String dateEnd = "20220831";
		
        /**
         * 1) CheckData 
         * 가져올거예요 CheckData
         * @param paramMap 
         * @return
        */
        selfChkList = selfChkService.retrieveCheckData(Cod, dateStart, dateEnd);printSelfChkList(selfChkList);
		
	}

	private static void printSelfChkList(List<SelfCheck> selfChkList) {
		SelfCheck selfChk = null;
      
		for(Iterator<SelfCheck> iter = selfChkList.iterator(); iter.hasNext();)
		{
			selfChk = iter.next();
			System.out.println(selfChk.getOperatorName() );
			System.out.println(selfChk.getCheckData()    );
			System.out.println(selfChk.getTpCod()        );
		}
	}
}

MyBatis 3 를 사용해서 여러 테이블에서 질의한 값을 하나의 VO 오브젝트로 저장한 리스트를 받아서 확인하는 과정을 진행 해 보았습니다.

 

이상.

참고 문서들
[1]https://javamana.com/2021/01/20210128182455104x.html
[2]https://stackoverflow.com/questions/33067816/mybatis-3-query-from-tables-without-relationship
[3]https://haenny.tistory.com/372
[4]https://stackoverflow.com/questions/4363808/how-do-you-handle-sql-mapping-for-multiple-tables-in-ibatis-and-java
[5]https://stackoverflow.com/questions/56789700/mybatis-how-to-join-multiple-columns-from-same-table
[6]https://stackoverflow.com/questions/56078196/using-mybatis-to-map-multiple-tables-to-a-single-collection
[7]https://stackoverflow.com/questions/28429324/how-to-map-multiple-beans-in-mybatis

 

 

Releases · mybatis/mybatis-3

MyBatis SQL mapper framework for Java. Contribute to mybatis/mybatis-3 development by creating an account on GitHub.

github.com

 

 

Releases · mybatis/mybatis-3

MyBatis SQL mapper framework for Java. Contribute to mybatis/mybatis-3 development by creating an account on GitHub.

github.com

 

MyBatis 자습 – CRUD 조작과 관계 매핑 – Part 1

CRUD 조작 MyBatis는 JDBC를 직접 사용하는 것과 비교 비교 할 수 없을 정도로 #데이터베이스 #...

blog.naver.com

 

 

 

오라클연결- 10g

다음은 오라클 10g를 중심으로 iBatisNet에서 오라클 접속하고 질의 하는 방법을 설명합니다. 목차 1. D...

blog.naver.com

 

728x90