Dynamic SQL (MyBatis 동적 SQL), AOP(Aspect Oriented Programming)
*22년 4월 한 달간 한국이러닝협회의 '실전 개발자를 위한 Spring Framework'를 수강하고 정리한 내용입니다
*모든 이미지의 출처는 한국이러닝협회의 '실전 개발자를 위한 Spring Framework'에 있습니다
1. MyBatis 동적 SQL
1) Dynamic SQL
- 검색조건에 따라 검색해야 하는 SQL문이 달라지기 때문에 이를 처리하기 위해서 동적 SQL이 사용됨
2) MyBatis의 표현식
(1) if - MyBatis에서 가장 공통적으로 사용되는 요소
* 아래 구문은 파라미터 중 title에 값이 존재할 경우 and title like #{title} 구문을 본 쿼리문에 포함시킨다.
<select id="findActiveBlogWithTitleLike" resultType="Blog">
select * from blog where state = 'ACTIVE'
<if test="title != null">
and title like #{title}
</if>
</select>
* 아래 구문은 author와 author.name 파라미터에 값이 존재할 경우 and author_name like #{author.name} 구문을 쿼리문에 포함시킴
* 파라미터 안에 다른 타입(클래스)가 포함되어 캡슐화를 이룰 경우, .(dot) 연산자로 접근할 수 있다.
<select id="findActiveBlogLike" resultType="Blog">
select * from blog where state = 'ACTIVE'
<if test="title != null">
and title like #{title}
</if>
<if test="author != null and author.name != null">
and author_name like #{author.name}
</if>
<select>
(2) choose (when, otherwise)
- 여러 구문 중 하나만 실행
- title 파라미터의 값이 존재하면 and title like #{title} 구문을 포함
- author와 author.name 파라미터 값이 존재한다면 and author_name like #{author.name} 구문을 포함
둘 다 존재하지 않는다면 and featured=1 구문을 포함
<select id="findActiveBlogLike" resultType="Blog">
select * from blog where state = 'ACTIVE'
<choose>
<when test="title != null">
and title like #{title}
</when>
<when test="author != null and author.name != null">
and author_name like #{author.name}
</when>
<otherwise>
and featured=1
</otherwise>
</choose>
</select>
(3) trim (where,set) - 여러 구문 중 하나만 실행
- <where> </where>는 내부에 컨텐츠가 존재할 때 where 키워드를 포함함
내부에 컨텐츠가 존재하지 않으면 where 키워드를 쓰지 않음
* where 다음 and 혹은 or가 바로 올 경우, 다음과 같이 and/or 키워드를 삭제함
<trim prefix="WHERE" prefixOverrides="AND | OR">
...
</trim>
* 아래 구문과 같이 trim을 바로 사용할 수도 있음
<select id="findActiveBlogLike" resultType="Blog">
select *
from BLOG
<trim prefix="WHERE" prefixOverrids="AND">
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
title like #{title}
</if>
<if test="author != null and author.name != null">
author_name like #{author.name}
</if>
</trim>
</select>
* 아래 구문은 잘못 사용된 예
<select id="findActiveBlogLike" resultType="Blog">
select *
from BLOG
where
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
and title like #{title}
</if>
<if test="author != null and author.name != null">
and author_name like #{author.name}
</if>
</select>
* 만약 아무런 파라미터도 없다면 다음과 같은 쿼리가 만들어짐
select *
from blog
where
(4) foreach
- Dynamic Query에서 공통적으로 필요한 기능은 Collection의 반복
- collection 속성은 파라미터가 List일 경우는 list, 파라미터가 Array(배열)일 경우는 array를 사용
- in 키워드 사용 시 종종 사용됨
<select id="selectPostIn" resultType="domain.blog.Post">
select * from post p where id in
<foreach item="item" index="index" collection="list" open="("separator=","close=")">
#{item}
</foreach>
</select>
3) 동적 SQL 작성 시 유의사항
- MyBatis 구문을 이용하여 SQL문이 실행 시에 변경되기 때문에, 모든 케이스에 대해 테스트 진행해야 함
- 동적 SQL문이 없는 상태에서 정상적인 실행을 확인한 후, 동적 SQL문을 추가해서 개발
2. AOP(Aspect Oriented Programming)
1) AOP의 개요
(1) 핵심기능과 부가기능
- 핵심기능(Core Concerns): 업무(Biz) 로직을 포함하는 기능
- 부가기능(Cross-cutting Concerns): 핵심기능을 도와주는 부가적인 기능(로깅, 보안 등)
- 객체지향의 기본 원칙을 적용하여도, 핵심기능에서 부가기능을 분리해서 모듈화하는 것은 매우 어려움
(2) AOP의 정의 및 특징
- 애플리케이션에선의 관심사의 분리(=기능의 분리)
=> 핵심적인 기능에서 부가적인 기능을 분리하고,
분리한 부가기능을 애스펙트(Aspect)라는 독특한 모듈 형태로 만들어서(정의해서) 설계하고 개발하는 방법
- OOP(객체지향 프로그래밍)를 적용해도 핵심기능에서 부가기능을 쉽게 분리된 모듈로 작성하기 어려웠던 문제점을 해결
- 핵심기능에서 부가기능을 분리해서, 핵심기능을 설계하고 구현할 때 객체지향적인 가치를 지킬 수 있도록 도와주는 개념
2) AOP 용어
(1) 애스펙트(Aspect)
"Advice + PointCut = Aspect"
- AOP의 기본 모듈로, 싱글톤 형태의 객체로 존재
- 부가기능을 정의한 코드인 어드바이스(Advice)와 어드바이스를 어디에 적용할지 결정하는 포인트컷(PointCut)을 합침
- AOP 개념을 적용하면, 핵심기능 코드 사이에 침투된 부가기능을 독립적인 애스펙트로 구분해 낼 수 있음
- 구분된 부가기능 애스펙트를 런타임 시에 필요한 위치에 동적으로 참여하게 할 수 있음
(2) 타깃(Target)
- 핵심기능을 담고 있는 모듈로, 타깃은 부가기능을 부여할 대상이 됨
(3) 어드바이스(Advice)
- 타깃에 제공할 부가기능을 담고 있는 모듈
(4) 조인 포인트(Join Point)
- 어드바이스가 적용될 수 있는 위치
- 타깃 객체가 구현한 인터페이스의 모든 메소드는 조인 포인트가 됨
(5) 포인트 컷(PointCut)
- 어드바이스를 적용할 타깃의 메소드를 선별하는 정규표현식
- 표현식은 execution으로 시작하고, 메소드의 Signature를 비교하는 방법을 주로 이용
(6) 어드바이저(Advisor)
- 어드바이저 = 어드바이스 + 포인트컷
- Spring AOP에서만 사용되는 특별한 용어
(7) 위빙(Weaving)
- 포인트컷에 의해 결정된 타깃의 조인 포인트에 부가기능(어드바이스)을 삽입하는 과정
- AOP가 핵심기능(타깃)의 코드에 영향을 주지 않으면서,
필요한 부가기능(어드바이스)을 추가할 수 있도록 해주는 핵심적인 처리과정
3) Spring AOP의 특징
(1) Spring은 프록시(Proxy) 기반 AOP를 지원함
- Spring은 타깃(target) 객체에 대한 프록시를 만들어 제공함
- 타깃을 감싸는 프록시는 실행시간(Runtime)에 생성됨
- 프록시: 어드바이스를 타깃 객체에 적용하면서 생성되는 객체
(2) 프록시(Proxy)가 호출을 가로챈다(Intercept)
- 전처리 어드바이스: 프록시는 타깃 객체에 대한 호출을 가로챈 다음,
어드바이스의 부가기능 로직을 수행하고 난 후에 타깃의 핵심기능 로직을 호출함
- 후처리 어드바이스: 타깃의 핵심기능 로직 메소드를 호출한 후에 부가기능(어드바이스)을 수행하는 경우가 있음
(3) Spring AOP는 메소드 조인 포인트만 지원함
- Spring은 동적 프록시를 기반으로 AOP를 구현하므로 메소드 조인포인트만 지원함
- 핵심기능(타깃)의 메소드가 호출되는 런타임 시점에만 부가기능(어드바이스)을 적용할 수 있음
- 반면에 AspectJ 같은 고급 AOP 프레임워크를 사용하면
객체의 생성, 필드값의 조회와 조작, static 메소드 호출 및 초기화 등의 다양한 작업에 부가기능을 적용할 수 있음