MyBatis의 소개와 설정
1. MyBatis란?
SQL Mapping Framework - Easy & Simple
자바 코드로부터 SQL문을 분리해서 관리
매개변수 설정과 쿼리 결과를 읽어오는 코드를 제거
작성할 코드가 줄어서 생산성 향상 & 유지 보수 편리
2. SqlSessionFactoryBean과 SqlSessionTemplate
SqlSessionFactory - SqlSession을 생성해서 제공
SqlSession - SQL 명령을 수행하는데 필요한 메소드 제공
(둘 다 인터페이스이며 mybatis에서 제공)
(root-context.xml에 두 인터페이스의 빈을 등록해야함)
SqlSessionFactoryBean - SqlSessionFactory를 Spring에서 사용하기 위한 빈 (mybatis-spring에서 제공)
SqlSessionTemplate - SQL 명령을 수행하는데 필요한 메소드 제공. thread-safe
(SqlSessionTemplate를 여러 Dao에서 공유해서 쓸 수 있음. 멀티쓰레드에 안전함)
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"/>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
(4번째 줄에서 *Mapper.xml 위치를 지정해줘야 함)
3. SqlSession의 주요 메소드
한 행(row)를 가져올 땐 selectOne
여러 행을 가져올 땐 selectList, selectMap 을 사용. 보통 List를 많이 사용함
Object parameter는 넘겨줄 값이 담긴 객체인데, User 객체에 담아서 주거나 Map에 담아서 주면 된다.
넘겨줄 값이 없으면 parameter 없이 줌.
4. Mapper XML의 작성
[ boardMapper.xml ]
<?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 namespace="com.fastcampus.ch4.dao.BoardMapper">
<select id="count" resultType="int">
SELECT count(*) FROM board
</select>
<delete id="deleteAll">
DELETE FROM board
</delete>
<delete id="delete" parameterType="map">
DELETE FROM board WHERE bno = #{bno} and writer = #{writer}
</delete>
<insert id="insert" parameterType="BoardDto">
INSERT INTO board
(title, content, writer)
VALUES
(#{title}, #{content}, #{writer})
</insert>
<select id="selectAll" resultType="BoardDto">
SELECT bno, title, content, writer, view_cnt, comment_cnt, reg_date
FROM board
ORDER BY reg_date DESC, bno DESC
</select>
<sql id="selectFromBoard">
SELECT bno, title, content, writer, view_cnt, comment_cnt, reg_date
FROM board
</sql>
<select id="select" parameterType="int" resultType="BoardDto">
<include refid="selectFromBoard"/>
WHERE bno = #{bno}
</select>
<select id="selectPage" parameterType="map" resultType="BoardDto">
<include refid="selectFromBoard"/>
ORDER BY reg_date DESC, bno DESC
LIMIT #{offset}, #{pageSize}
</select>
<update id="update" parameterType="BoardDto">
UPDATE board
SET title = #{title}
, content = #{content}
, up_date = now()
WHERE bno = #{bno}
</update>
<update id="updateCommentCnt" parameterType="map">
UPDATE board
SET comment_cnt = comment_cnt + #{cnt}
WHERE bno = #{bno}
</update>
<update id="increaseViewCnt" parameterType="int">
UPDATE board
SET view_cnt = view_cnt + 1
WHERE bno = #{bno}
</update>
</mapper>
public String getServerTime() throws Exception {
return session.selectOne(namespace+"now");
} // T selectOne(String statement)
boardMapper.xml에 등록된, namespace가 일치하고 id="now" 인 sql문을 실행함.
boardMapper.xml에서
resultType은 반환 타입을 의미함.
반환 타입이 항상 일정하면 resultType을 생략할 수 있음.
(예를 들면 id="insert"의 경우, insert는 항상 int를 반환하므로 생략되는 것을 볼 수 있음)
parameterType은 입력으로 들어가는 값이 담긴 클래스 객체를 의미함.
해당 클래스의 getter 메소드를 이용하기 때문에, 클래스 객체를 주면 필요한 값들을 자동으로 입력하게 된다.
id="select"의 경우 parameterType이 int(원래는 Integer, 별명이 int임)인데,
위 예제의 경우 게시물 번호를 의미하기 때문에 게시물 번호를 입력하면 BoardDto의 해당 select 값들을 얻을 수 있음.
5. <typeAliases>로 이름 짧게 하기 - https://mybatis.org/mybatis-3/configuration.html#typeAliases
<typeAliases>
<typeAlias alias="BoardDto" type="com.fastcampus.ch4.domain.BoardDto"/>
<typeAliases>
Integer를 int라는 별명으로 사용하듯이
별명을 직접 만들어서 사용할 수 있음.
별명은 대소문자 구별이 없음. 대문자나 소문자나 같음.
MyBatis로 DAO작성하기
1. BoardDao의 작성
1) DB테이블 생성
2) Mapper XML & DTO 작성
3) DAO 인터페이스 작성
4) DAO 인터페이스 구현 & 테스트
2. DTO란? Data Transfer Object
계층간의 데이터를 주고 받기 위해 사용되는 객체
3. #{}와 ${}의 차이
#{} 는 PreparedStatement를 쓰고 (VALUES의 ? 값에만 사용할 수 있음)
${} 는 Statement를 씀 (sql문 전체에 사용 가능)
4. XML의 특수 문자 처리
XML내의 특수 문자 (<, >, &, ...)는 < >로 변환 필요
또는 특수문자가 포함된 쿼리를 <![CDATA[ 내용 ]]> 으로 감싼다
package com.fastcampus.ch4.dao;
import com.fastcampus.ch4.domain.BoardDto;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Repository
public class BoardDaoImpl implements BoardDao {
@Autowired
SqlSession session;
String namespace = "com.fastcampus.ch4.dao.BoardMapper.";
@Override
public int count() throws Exception {
return session.selectOne(namespace+"count");
} // T selectOne(String statement)
@Override
public int deleteAll() {
return session.delete(namespace+"deleteAll");
} // int delete(String statement)
@Override
public int delete(Integer bno, String writer) throws Exception {
Map map = new HashMap();
map.put("bno", bno);
map.put("writer", writer);
return session.delete(namespace+"delete", map);
} // int delete(String statement, Object parameter)
@Override
public int insert(BoardDto dto) throws Exception {
return session.insert(namespace+"insert", dto);
} // int insert(String statement, Object parameter)
@Override
public List<BoardDto> selectAll() throws Exception {
return session.selectList(namespace+"selectAll");
} // List<E> selectList(String statement)
@Override
public BoardDto select(Integer bno) throws Exception {
return session.selectOne(namespace + "select", bno);
} // T selectOne(String statement, Object parameter)
@Override
public List<BoardDto> selectPage(Map map) throws Exception {
return session.selectList(namespace+"selectPage", map);
} // List<E> selectList(String statement, Object parameter)
@Override
public int update(BoardDto dto) throws Exception {
return session.update(namespace+"update", dto);
} // int update(String statement, Object parameter)
@Override
public int increaseViewCnt(Integer bno) throws Exception {
return session.update(namespace+"increaseViewCnt", bno);
} // int update(String statement, Object parameter)
}
boardMapper.xml 에 등록한 sql문을 활용하여 BoardDaoImpl 클래스를 만들었다.
이렇게 만든 BoardDao를 활용하여 Service를 만든다.
package com.fastcampus.ch4.service;
import com.fastcampus.ch4.dao.*;
import com.fastcampus.ch4.domain.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
import java.util.*;
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
BoardDao boardDao;
@Override
public int getCount() throws Exception {
return boardDao.count();
}
@Override
public int remove(Integer bno, String writer) throws Exception {
return boardDao.delete(bno, writer);
}
@Override
public int write(BoardDto boardDto) throws Exception {
return boardDao.insert(boardDto);
}
@Override
public List<BoardDto> getList() throws Exception {
return boardDao.selectAll();
}
@Override
public BoardDto read(Integer bno) throws Exception {
BoardDto boardDto = boardDao.select(bno);
boardDao.increaseViewCnt(bno);
return boardDto;
}
@Override
public List<BoardDto> getPage(Map map) throws Exception {
return boardDao.selectPage(map);
}
@Override
public int modify(BoardDto boardDto) throws Exception {
return boardDao.update(boardDto);
}
}
출처 : 스프링의 정석 : 남궁성과 끝까지 간다
'Spring & SpringBoot > Spring' 카테고리의 다른 글
220511 Spring - Chapter 4. MyBatis로 게시판 만들기(Part.3) (0) | 2022.05.12 |
---|---|
220510 Spring - Chapter 4. MyBatis로 게시판 만들기(Part.2) (0) | 2022.05.11 |
220506 Spring - Chapter 3. Spring DI와 AOP (Part. 6) (0) | 2022.05.07 |
220505 Spring - Chapter 3. Spring DI와 AOP (Part. 5) (0) | 2022.05.06 |
220504 Spring - Chapter 3. Spring DI와 AOP (Part. 4) (0) | 2022.05.05 |