참고
마이바티스
NOTE
Mybatis는 자바 오브젝트와 SQL사이의 자동 매핑 기능을 지원하는 ORM(Object reliational Mapping)프레임워크이다.
•
xml문서를 통해 작성하므로 편리하게 작성한다.
•
mybatis는 동적쿼리를 작성하기 편리하다.
퍼시스턴트
•
객체가 생성되면 메모리에 올라간다
•
객체를 이용해서 다루는 데이터들은 객체가 사라지면 함께 사라진다
•
이렇게 일회용으로 버려지는 데이터들을 유지하기위해서 어딘가에 저장해야하는데 이렇게하면 나중에 객체가 다시 생성되면 재사용이 가능하다
( 사라지기 전의 상태로 돌아간다 → 영속성(Persistence)라고 함 )
JDBC | MyBatis 비교
NOTE
String sql = "select id, item_name, price, quantity from item";
//동적 쿼리
if (StringUtils.hasText(itemName) || maxPrice != null) {
sql += " where";
}
boolean andFlag = false;
if (StringUtils.hasText(itemName)) {
sql += " item_name like concat('%',:itemName,'%')";
andFlag = true;
}
if (maxPrice != null) {
if (andFlag) {
sql += " and";
}
sql += " price <= :maxPrice";
}
log.info("sql={}", sql);
return template.query(sql, param, itemRowMapper());
Java
복사
JDBC 동적 쿼리작성
<select id="findAll" resultType="Item">
select id, item_name, price, quantity
from item
<where>
<if test="itemName != null and itemName != ''">
and item_name like concat('%',#{itemName},'%')
</if>
<if test="maxPrice != null">
and price <= #{maxPrice}
</if>
</where>
</select>
XML
복사
Mybatis 동적 쿼리작성 (가독성부터 좋아보임)
마이바티스 적용
NOTE
Mapping 파일에 기재된 SQL을 호출하기 위한 인터페이스
@Mapper
public interface ItemMapper{
void save(Item item)
// param이 2개이상이면 명시해줘야 한다.
void update(@Param("id") Long id, @Param("updateParam") ItemUpdateDto updateParam)
List<Item> findAll(ItemSearchCond ItemSearch);
Optional<Item> findById(Long id);
}
Java
복사
@Mapper를 통해 xml의 해당 SQL을 실행시킬 수 있다.
@Repository
@RequiredArgsConstructor
public class MyBatisItemRepository implements ItemRepository {
private final ItemMapper itemMapper;
@Override
public Item save(Item item) {
itemMapper.save(item);
return item;
}
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
itemMapper.update(itemId, updateParam);
}
@Override
public Optional<Item> findById(Long id) {
return itemMapper.findById(id);
}
@Override
public List<Item> findAll(ItemSearchCond cond) {
return itemMapper.findAll(cond);
}
}
Java
복사
mapper를 사용하는 Repository
<?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의 패키지경로! ?>
<mapper namespace="hello.itemservice.repository.mybatis.ItemMapper">
<? 저장쿼리(useGeneratedKeys - 자동키 생성) ?>
<? #{} 로 파라미터가 넘어간다. ?>
<insert id="save" useGeneratedKeys="true" keyProperty="id">
insert into item (item_name, price, quantity)
values (#{itemName}, #{price}, #{quantity})
</insert>
<? 업데이트 쿼리 ?>
<update id="update">
update item
set item_name=#{updateParam.itemName},
price=#{updateParam.price},
quantity=#{updateParam.quantity}
where id = #{id}
</update>
<? 검색 쿼리 ?>
<? resultType을 통해 결과를 자동반환 ?>
<select id="findById" resultType="Item">
select id, item_name, price, quantity
from item
where id = #{id}
</select>
<? 전체검색 쿼리, 동적쿼리(where) ?>
<? <where>는 적절하게 where을 만들어준다. if가 성공하면 생성, 아니면 생성하지않음 ?>
<select id="findAll" resultType="Item">
select id, item_name, price, quantity
from item
<where>
<? 아이템 이름값이 있다면 조건추가 ?>
<if test="itemName != null and itemName != ''">
and item_name like concat('%',#{itemName},'%')
</if>
<? 가격값이 있다면 조건추가 ?>
<if test="maxPrice != null">
and price <= #{maxPrice}
</if>
</where>
</select>
</mapper>
XML
복사
xml파일 위치는 mapper패키지명과 동일해야한다.
마이바티스 경로, 특수문자
NOTE
XML 파일 경로 수정하기
XML 파일을 원하는 위치에 두고 싶으면 application.properties에 다음과 같이 설정하면 된다.
•
mybatis.mapper-locations=classpath:mapper/**/*.xml
•
이렇게 하면 resources/mapper 를 포함한 그 하위 폴더에 있는 XML을 XML 매핑 파일로 인식한다. 이 경우 파일 이름은 자유롭게 설정해도 된다.
XML 특수문자
•
< : &lit
•
> : &ㅎㅅ
•
& : &
CDATA 구문 문법을 사용해서 특수문자 사용하기
<where>
<if test="itemName != null and itemName != ''">
and item_name like concat('%',#{itemName},'%')
</if>
<if test="maxPrice != null">
<![CDATA[
and price <= #{maxPrice}
]]>
</if>
</where>
XML
복사
CDATA 사용하기( 단 해당 구문안에서는 XML태그가 일반 문자로 인식된다.)
마이바티스 분석
NOTE
ItemMapper: 매퍼 인터페이스의 구현체가 없는데 어떻게 동작하는가?
동적 프록시 기술로 구현체를 만들어준다.
매퍼 구현체
•
마이바티스 스프링 연동 모듈이 만들어주는 ItemMapper 의 구현체 덕분에 인터페이스 만으로 편리하게 XML의 데이터를 찾아서 호출할 수 있다.
•
원래 마이바티스를 사용하려면 더 번잡한 코드를 거쳐야 하는데, 이런 부분을 인터페이스 하나로 매우 깔끔하고 편리하게 사용할 수 있다.
•
매퍼 구현체는 예외 변환까지 처리해준다. MyBatis에서 발생한 예외를 스프링 예외 추상화인DataAccessException 에 맞게 변환해서 반환해준다. JdbcTemplate이 제공하는 예외 변환 기능을 여기서도 제공한다고 이해하면 된다.
정리
•
매퍼 구현체 덕분에 마이바티스를 스프링에 편리하게 통합해서 사용할 수 있다.
•
매퍼 구현체를 사용하면 스프링 예외 추상화도 함께 적용된다.
•
마이바티스 스프링 연동 모듈이 많은 부분을 자동으로 설정해주는데, 데이터베이스 커넥션, 트랜잭션과 관련된 기능도 마이바티스와 함께 연동하고, 동기화해준다.
동적쿼리
NOTE
Mapping 파일에 기재된 SQL을 호출하기 위한 인터페이스
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
XML
복사
if - 해당조건에 따라 추가할지 판단
<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>
XML
복사
choose, when, otherwise - java의 switch와 같은 개념
<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>
</where>
</select>
XML
복사
trim, where, set - 동적조건
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
<where>
<? open, close는 반복의 시작과 끝을 정의한다 ?>
<? ex) SELECT * FROM POST P WHERE ID in (1, 2, 3) ?>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>
XML
복사
foreach - 컬렉션 반복처리
기타쿼리
NOTE
애노테이션으로 SQL작성 가능
@Select("select id, item_name, price, quantity from item where id=#{id}")
Optional<Item> findById(Long id);
Java
복사
문자열 대체
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
Java
복사
문자 그대로를 처리? ⇒ SQL Injection이 들어올 수 있으므로 쓰지말자
SQL 조각
<sql id="userColumns">
"${alias}.id.${alias}.username,${alias}.password
</sql>
XML
복사
<sql>을 통한 코드 재사용
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/></include>,
<include refid="userColumns"><property name="alias" value="t2"/></include>
from some_table t1
cross join some_table t2
</select>
XML
복사
<include>를 활용해서 <sql>조각 사용가능
ResultMap(별칭관련)
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
XML
복사
resultMap을 통한 별칭연결