💡 MyBatis - 개발자들이 SQL 쿼리를 쉽게 작성하고 관리할 수 있도록 도와주는 퍼시스턴스 프레임워크입니다.
- 이를 사용하여 SQL 쿼리와 프로그래밍 코드를 분리하여 관리할 수 있어서 코드의 가독성과 재사용성을 높이고 유지 보수를 용이하게 합니다. - 또한 JDBC 코드의 복잡성을 추상화하고 SQL 쿼리의 실행 결과와 자바 객체에 매핑하기 위한 강력한 매핑 기능을 제공합니다.
[더 알아보기 ] 💡퍼시스턴스 프레임워크
- 데이터의 저장, 복원, 쿼리, 업데이트 등의 작업을 자동화해 주는 소프트웨어 라이브러리입니다. - 이를 사용하면 개발자는 데이터베이스에 대한 복잡한 코드를 작성하지 않아도 되며 이로 인해 개발시간을 단축하고 코드의 품질을 향상할 수 있습니다. - 대표적인 퍼시스턴스 프레임워크로는 Hibernate, MyBatis 등이 있습니다
💡 MyBatis와 iBatis의 차이는 무엇일까?
- iBatis 프로젝트가 중단되고 이를 기반으로 MyBatis가 개발되었습니다. - iBatis보다 MyBatis는 동적 SQL, 프로시저 호출, 고급 매핑 기능 등을 지원합니다.
- 해당 예시에서는 tb_user 테이블을 전체 조회하는 SQL문에서 WHERE 구문을 조건부 수행하는 구문입니다. - 해당 예시에서는 파라미터로 userId, userName, userEmail, userPw 값이 null이 아니고 빈값이 아닌 경우에 따라서 조건부 수행이 됩니다. - 각각 값이 유효하다면 WHERE 조건절의 다음 조건문으로 수행이 됩니다.
<!-- 사용자 정보를 조회합니다 -->
<selectid="selectUser"resultType="userDto">
SELECT *
FROM tb_user
WHERE 1=1
<iftest="userId != null and !userId.equals('')">
AND user_id = #{userId}
</if><iftest="userName != null and !userName.equals('')">
AND user_name = #{userName}
</if><iftest="userEmail != null and !userEmail.equals('')">
AND user_email = #{userEmail}
</if><iftest="userPw != null and !userPw.equals('')">
AND user_pw = #{userPw}
</if></select>
💡 [참고] test 속성에 주로 사용이 되는 동등 비교 연산자, 불일치 비교 연산자에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
💡 choose (when, otherwise) - Java에서 Switch문과 같은 기능을 수행하는 태그입니다. choose 태그 안에는 when과 otherwise 태그를 추가하며 when 만으로 구성이 될 수 있거나 otherwise가 추가된 태그로 구성이 될 수 있습니다.
- ‘otherwise’ 태그의 경우 ‘when’ 태그의 모든 조건이 충족되지 않을 경우 해당 태그의 내부 SQL문이 실행이 됩니다.
조건문
설명
choose
SQL의 CASE문과 비슷한 역할을 수행하는것 처럼 여러 개의 when 중에서 조건에 맞는 하나를 선택하여 실행하는 기능을 제공합니다.
when
choose 내에서 사용이 되며 주어진 조건이 참일 때 실행이 됩니다. 또한, 여러개의 when이 있는 경우 맨 처음 참인 조건을 갖는 when만 실행합니다.
otherwise
choose 내에서 사용되며 어떠한 when도 참이 아닐 때 실행이 됩니다. 즉, when 조건이 모두 거짓일 경우의 기본 동작합니다.
💡 기본구조
- choose 구문내에서 when ~ otherwise가 수행이 됩니다.
- 조건1이 참이면 ‘실행할 SQL 구문 1’이 실행되고 조건 2가 참이면 ‘실행할 SQL 구문 2’가 실행됩니다. 만약 어떠한 조건도 충족되지 않으면 “기본 실행 SQL 구문”이 실행됩니다.
- <choose>: 여러 개의 when 중에서 조건에 맞는 하나를 선택하여 실행하는 구조를 제공합니다. - <when test="조건">: 특정 조건이 충족될 때 수행되는 SQL 구문입니다. 여러 개의 when 구문이 있을 수 있으며, 처음으로 참인 조건을 갖는 when 구문만 실행됩니다. - <otherwise>: when 구문들 중 어떤 것도 충족되지 않을 때 실행되는 SQL 구문입니다. 즉, 모든 when 조건이 거짓일 경우 수행됩니다.
<choose>
<whentest="조건1">
실행할 SQL 구문1
</when><whentest="조건2">
실행할 SQL 구문2
</when><otherwise>
기본 실행 SQL 구문
</otherwise>
</choose>
- 해당 예시에서는 tb_user 테이블을 전체 조회하는 SQL문에서 ORDER BY 구문을 조건에 따라 동적 SQL문으로 처리하는 방법을 이용한 예시입니다. - 해당 SQL문에서 파라미터로 기본적으로 ‘cd’ 값이 null이 아닌 상태에 값이 ‘java’ 혹은 ‘kotlin’의 경우에 각각에 맞는 정렬을 수행하는 예시입니다. 또한 해당 경우에 맞지 않는 경우는 다른 정렬을 수행합니다.
<!-- 전체 코드를 조회합니다--><selectid="selectCodeList"resultType="codeDto">
SELECT t1.*
FROM tb_code t1
WHERE t1.use_yn = true
<choose><whentest="cd != null and cd == 'java'">
ORDER BY cd DESC
</when><whentest="cd != null and cd == kotlin">
ORDER BY cd ASC
</when><otherwise>
ORDER BY sort_order DESC
</otherwise></choose></select>
💡 trim - SQL 쿼리의 일부를 동적으로 제어하기 위한 기능입니다. 해당 태그로 감싸 있는 경우 조건에 만족하는 내용이 없다면 trim 태그는 수행되지 않습니다. - trim 태그는 where, set 등의 예약어를 사용하는 경우에 이를 조건에 따라 동적으로 적용할 수 있게 해 줍니다.
💡 Trim 속성 사용예시 :prefix - 해당 구문은 tb_code 테이블의 컬럼들을 동적으로 변경하는 SQL문입니다. - 해당 구문에서는 trim 태그 내의 if 태그의 조건이 하나라도 만족한다면 prefix=”SET” 속성으로 SET 구문을 생성하며, suffixOverrides 속성을 통해 마지막 “,”를 제거합니다. - 단 해당 구문에서 하나라도 수정하는 컬럼이 없다면 trim 태그는 생성되지 않고 오류가 발생할 수 있습니다.
💡 Trim 속성 사용예시: prefixOverrides - 해당 예시에서는 사용자 정보를 조건부 조회하는 SQL문입니다. - 해당 부분에서는 trim 태그를 사용하여 if 태그의 조건이 하나라도 존재한다면 AND 구문을 제거하고, 존재하지 않으면 생성하지 않도록 하는 구문을 구성하였습니다.
<!-- 사용자 정보를 조회합니다 --><selectid="selectUser"resultType="userDto">
SELECT *
FROM tb_user
WHERE
<trimprefixOverrides="AND "><iftest="userId != null">AND user_id = #{userId}</if><iftest="userName != null">AND userName = #{userName}</if></trim></select>
[참고] 💡 그러면 trim 내에서 두 개 모두 만족하는 경우 AND라는 값이 모두 사라지는가?
- 만약 'userId'와 'userName' 조건이 동시에 만족된다면, 첫 번째 조건 'userId' 앞의 'AND '는 제거되지만, 두 번째 조건 'uerName' 앞의 'AND '는 그대로 유지됩니다. - 따라서 두 조건이 모두 만족되면 SQL 구문은 WHERE user_id = #{userId} AND userName = #{userName}가 됩니다.
3.3. Trim 속성 사용예시: suffix
💡 Trim 속성 사용예시: suffix
- 해당 예시에서는 tb_user 테이블의 컬럼을 채우는 INSERT 구문입니다. - INSERT 구문에서도 일부 값만 동적으로 추가하는 경우 trim 태그를 이용하여서 전달받은 파라미터 값에 따라 동적으로 컬럼 값을 추가합니다. - 단 해당 구문에서 하나라도 추가하는 컬럼이 없다면 trim 태그는 생성되지 않고 오류가 발생할 수 있습니다.
- WHERE절을 동적으로 만들어주는 구문으로 where 태그 내에 조건이 참인 경우에만 해당 조건을 SQL문장에 포함시킵니다.
<where>
<iftest="조건1">
AND 실행할 SQL 구문1
</if><iftest="조건2">
AND 실행할 SQL 구문2
</if>
</where>
💡 사용예시 - 조건부 코드 리스트를 조회하는 SQL문입니다.
- 해당 부분에서는 where 태그로 동적 SQL문을 구성합니다. - if 태그에 만족하는 값이 있을 경우 WHERE 절이 생성이 되고 if 태그의 조건이 있는 경우 WHERE 절이 생성이 되며 첫 번째 마주한 SQL문에서는 AND / OR을 제거하고 WHERE절이 생성이 됩니다.
<!--코드를 조회합니다-->
<selectid="selectCode"resultType="codeDto">
SELECT t1.grp_cd
, t1.cd
, t1.grp_cd_nm
, t1.cd_nm
FROM public.tb_code t1
<where><iftest="cd != null">
AND cd = #{cd}
</if><iftest="grpCdNm != null">
AND grp_cd_nm = #{grpCdNm}
</if><iftest="cdNm != null">
AND cd_nm = #{cdNm}
</if><iftest="sortOrder != null">
AND sort_order= #{sortOrder}
</if><iftest="useYn != null">
AND use_yn= #{useYn}
</if></where>
- 해당 부분에서 foreach 태그를 통해 list로 들어온 데이터를 처리합니다. - 예를 들어 item = [”java”, “kotlin”, “node”]와 같은 데이터가 수행될 경우 IN (”java”, “kotlin”, “node”)으로 구성되어 수행됩니다.
<!-- 코드 값에 따라 코드 리스트를 전체 조회합니다.--><selectid="selectCodeByCd"resultType="codeDto">
SELECT
t1.grp_cd
, t1.cd
, t1.grp_cd_nm
, t1.grp_cd
, t1.grp_cd_nm
, t1.cd_nm
, t1.sort_order
FROM tb_code t1
WHERE t1.use_yn = true
AND t1.cd IN
<foreachitem="item"index="index"collection="list"open="("separator=","close=")">
#{item}
</foreach></select>
- name 속성은 변수의 이름을 지정하며, value 속성은 변수에 할당할 값을 지정합니다. 이 값은 OGNL 표현식이 될 수 있습니다.
<bind name="변수명" value="OGNL 표현식" />
[ 더 알아보기] 💡 OGNL(Object-Graph Navigation Language) 표현식
- 객체 그래프를 탐색하기 위한 표현식 언어입니다. OGNL은 자바 객체의 속성에 접근하거나 메서드를 호출하는 데 사용되며, 광범위한 연산, 타입 변환, 컬렉션 처리 등 많은 기능을 제공합니다.
💡 OGNL(Object-Graph Navigation Language) 표현식 사용예시
- name : 'name'이라는 이름의 속성 값에 접근합니다. - person.birthday.month : 'person' 객체의 'birthday' 속성 내의 'month' 속성 값에 접근합니다. - @com.example.MyClass@MY_CONSTANT : 'com.example.MyClass'의 'MY_CONSTANT'라는 이름의 정적 필드에 접근합니다
💡 사용예시
- tb_code 테이블을 조회하는데 조건부 조회를 수행하는 SQL문입니다.
- 해당 SQL문에서는 bind 태그를 통해 매핑하려는 이름을 속성 name로 지정하고 value 값에 OGNL 표현식을 통해 지정합니다. - 기본적으로 파라미터로 넘어오는 데이터는 ‘_parameter’로 매핑이 되며 해당 값에서 getter로 cdNm이라는 값을 가져와 Like 패턴을 만듭니다. - 이러한 패턴을 기반으로 동적 Like 문을 만듭니다.
<!-- 코드 이름에 LIKE 조건으로 코드 리스트를 전체 조회합니다.-->
<selectid="selectCodeByCdNm"resultType="codeDto"><bindname="pattern"value="'%' + _parameter.getCdNm() + '%'"/>
SELECT t1.grp_cd
, t1.cd
, t1.grp_cd_nm
, t1.grp_cd
, t1.grp_cd_nm
, t1.cd_nm
, t1.sort_order
FROM tb_code t1
WHERE t1.use_yn = true
AND t1.cd_nm LIKE #{pattern}
</select>
💡 sql - 재사용 가능한 SQL 조각을 정의하는 데 사용됩니다. 이 태그를 사용하면 동일한 SQL 조각을 여러 매퍼에서 사용할 수 있으므로 코드의 중복을 줄이는데 도움이 됩니다.
- sql 태그의 id 속성은 SQL 조각의 식별자로 사용되며, 이를 include 태그의 refid 속성에 지정하여 SQL 조각을 참조할 수 있습니다. - sql 태그 내부에는 동적 SQL 구문도 포함될 수 있습니다. 이 경우, include 태그를 사용하여 SQL 조각을 참조할 때 동적 SQL 구문에 필요한 값을 전달할 수 있습니다.
속성
설명
id
재사용할 SQL 조각의 고유 식별자를 지정합니다.
parameterType
SQL 조각에서 사용할 파라미터의 타입을 지정합니다.
databaseId
SQL 조각이 특정 데이터베이스에서만 사용될 경우, 해당 데이터베이스의 ID를 지정합니다.
- 하나의 SQL 구문을 여러 SQL 맵퍼에 재사용할 수 있도록 하는 기능입니다. - 이는 중복 코드를 줄이고, 코드의 가독성과 유지 보수성을 높이는데 도움이 됩니다. include를 사용하면, SQL 구문을 외부 XML 파일에 정의하고, 이를 필요한 SQL 맵퍼에서 참조하여 사용할 수 있습니다.