[Mybatis] Mybatis 기초
특징
- 자원 생성 해제 필요 X
- 파라미터, 결과셋 설정 코드 X
- SQL문을 따로 관리(xml or 인터페이스)
- 구성요소 5가지 : 설정파일, 매퍼, 파라미터타입(parameterType), 결과타입(resultType),결과매핑(resultMap)
-
파라미터, 결과 타입 : Map객체, Java 모델 클래스, 원시타입
- 속성명과 변수명이 다를때 맵핑하는 방법은 resultMap을 사용하거나 Alias를 사용함 (Alias 권장)
- #{} 와 ${}의 차이점
- # : 문자면 ‘ ’를 달아줌 (숫자의경우 ‘ ‘을 달지않음)
- $ : 어떠한 경우도 ‘ ‘을 달지않음
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
매퍼 설정
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/test
username: sa
mybatis:
type-aliases-package: hello.itemservice.domain
configuration.map-underscore-to-camel-case: true
ItemMapper
- MyBatis 매퍼 XML을 호출해주는 인터페이스
- 이 인터페이스의 메서드를 호출하면 같은 이름을 갖는 id의 SQL이 실행된다
@Mapper
public interface ItemMapper {
void save(Item item);
void update(@Param("id") Long id, @Param("updateParam") ItemUpdateDto updateParam);
Optional<Item> findById(Long id);
List<Item> findAll(ItemSearchCond itemSearch);
}
ItemMapper.xml (매퍼 XML)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="hello.itemservice.repository.mybatis.ItemMapper"> <!-- Mapper Interface -->
<cache />
<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>
<select id="findById" resultType="Item"> <!-- type-aliases-package 위치 -->
select id, item_name, price, quantity
from item
where id = #{id}
</select>
<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>
→ #{}를 사용할 때 parameterType이 hashmap일경우 key값, DTO일경우 getter를 의미함
Repository
@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);
}
}
요소
- sql : 재사용 가능한 sql구문 정의 (id부여)
-
요소를 사용하여 SQL에 삽입
-
<sql id="BaseColumns">
comment_no AS commentNo,
user_id AS userId,
comment_content AS commentContent,
reg_date AS regDate
</sql>
- select
<select id="selectComment" parameterType="hashmap" resultType="mybatis.Comment">
SELECT
<include refid="BaseColumns" />
FROM comment
</select>
- insert, update, delete
- result가 없으므로 파라미터타입만 기입 (resultType, resultMap 필요 X)
<update id="insertComment" parameterType="Comment">
UPDATE tcomment SET comment_content = #{commentContent} WHERE comment_no = #{commentNo}
</update>
- where : where절 사용
- SQL구문에 WHERE를 추가, 게다가 구문이 AND 나 OR로 시작하면 그 구문을 지워줌
- if
<where>
<if test="commentNo != null">
comment_no = #{commentNo}
</if>
<if test="userId != null">
AND user_id = #{userId}
</if>
</where>
- choose, when, otherwise : switch-case-default 구문
<select id="selectCommentByConditionChoose" parameterType="hashmap" resultType="Comment">
SELECT comment_no AS commentNo, user_id AS userId, comment_content AS commentContent, reg_date AS regDate FROM tcomment
<choose>
<when test="commentNo != null">
WHERE comment_no = #{commentNo}
</when>
<when test="userId != null"> <!-- 첫번째 when에 걸릴경우 실행되지 않음 -->
WHERE user_id = #{userId}
</when>
<otherwise> <!-- 첫번째 when에 걸릴경우 실행되지 않음 -->
WHERE comment_no = 1 AND user_id = 'from'
</otherwise>
</choose>
</select>
- foreach : IN 구문에 많이 사용함
- collection : 배열 or 컬렉션
- item : each값
- index : 인덱스
- separator : 각 값의 구분자
- open, close : 시작과 끝에 삽입할 문자
<select id="selectCommentByConditionForeach" parameterType="hashmap" resultType="Comment">
SELECT comment_no AS commentNo, user_id AS userId, comment_content AS commentContent, reg_date AS regDate FROM tcomment
<where>
<if test="commentNos != null">
comment_no IN
<foreach collection="commentNos" item="commentNo" index="index" open="(" close=")" separator=", "> <!-- (?, ?) -->
#{commentNo} <!-- item값 -->
</foreach>
</if>
</where>
</select>
- selectKey : selectKey 구문이 먼저 실행되고 keyProperty에 결과를 넣은 후 그아래 SQL문이 실행됨
- keyProperty : selectKey 구문의 결과가 셋팅될 프로퍼티
- order : selectKey 구문의 순서 설정, SQL이 수행되기 전(BEFORE)인지 후(AFTER)인지
<insert id="insertCommentKey" parameterType="Comment">
<selectKey keyProperty="commentNo" resultType="long" order="BEFORE">
SELECT max(comment_no)+1 FROM tcomment
</selectKey>
INSERT INTO tcomment(comment_no, user_id, comment_content, reg_date)
VALUES (#{commentNo}, #{userId}, #{commentContent}, #{regDate})
</insert>