Spring07_MyBatis
myBatis
- 기존에는 SQL 쿼리를 DAO에 직접 써서 DB에 접근했다.
- 항상 DB접근, PreparedState객체 등 같은 코드가 계속 앞뒤로 들어가게됨
- DB에서 쿼리만 제어해줄 수 있고, 날아오는 파라미터를 제어하는 Java로 만든 프레임워크
- 2010년 Apache(iBatis)에서 Google(myBatis)로 변경
- JDBC코딩을 위한 일반화된 프레임 워크
- SQL을 Java가 아닌 XML코드로 따로 분리
- SQL의 실행 결과를 Map 또는 VO로 자동 매핑
- SQL을 XML이나 인터페이스 내에 Annotation을 활용하여 처리
- 적용
- SqlMapConfig파일(환경설정 파일)과 Mapper파일(실제 쿼리를 적용할 파일)이 필요( XML )
- SqlSession객체를 얻어온 다음 myBatis와 연동
1. 환경설정(Console모드)
- MyBatis
- 시작하기 에서 jar파일(3.5.7) 다운로드
- lib 폴더 만들어서 파일 복붙 후 BuildPath 라이브러리 추가
- ojdbc8.jar 파일도 lib에 복붙 후 BuildPath 라이브러리 추가
2. XML을 이용한 방법
mybatis-config.xml
- 환경설정파일
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- <mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers> -->
</configuration>
- driver, url, username, password는 바뀔 수도 있는 값이다.
- properties 파일에 넣어두고 그때그때 바꾸어준다.
- mybatic-config.xml파일에서
typeAlias
를 지정하면 VO 객체를 간격하게 사용할 수 있다.
<typeAliases>
<typeAlias type="kr.ac.kopo.board.BoardVO" alias="boardVO"/>
</typeAliases>
db.properties
- db접근 정보를 담은 파일
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:xe
jdbc.user=scott
jdbc.password=tiger
- 위와 같이 설정해주면 아래와 같이
mybatis-config.xml
를 수정한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties" />
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- <mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers> -->
</configuration>
MyConfig.java
- MyConfig객체가 생성되면 xml 파일을 읽고 sqlSessionFactory와 SqlSession객체를 얻어옴
- DB접근
package kr.ac.kopo;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyConfig {
private SqlSession session;
public MyConfig() {
// 객체 생성시 바로 실행되도록
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession();
//System.out.println(session);
}catch (Exception e) {
e.printStackTrace();
}
}
public SqlSession getInstance() {
// 외부에서 접근할 수 있도록 session객체 얻어오는 메소드
return session;
}
}
MyBatisMain.java
- MyConfig.java객체를 생성
package kr.ac.kopo;
import org.apache.ibatis.session.SqlSession;
public class MyBatisMain {
public static void main(String[] args) {
SqlSession session = new MyConfig().getInstance();
System.out.println(session);
}
}
mapper파일
- 실제 쿼리를 적용할 파일
- 태그종류
- select
resultType
: select했을 때 받아오는 값의 타입 지정.
- insert
- update
- delete
- resultMap
- select
- 속성 종류
- 구문을 구분하는 속성은
id
속성이다. parameterType
: 객체로부터 날아온 객체의 type- parameterType=”kr.ac.kopo.board.BoardVO”
- 객체 링크확인
- 구문을 구분하는 속성은
<select id="selectAll">
select *
from t_board
</select>
<select id="selectByNo">
select *
from t_board
where no = 5
</select>
- mapper파일이 하나가 아닐 수도 있다.
mapper1.xml
파일에id="selectAll"
이 있고mapper2.xml
에도id="selectAll"
이 있을수도 있음- namespace (package와 같은 역할) 태그를 붙여주면 구분할 수 있음
<mapper namespace="member.dao">
: member.dao의 selectAll이라는 의미
- VO객체 변수이름과 컬럼명이 다를 때 맞춰주고 싶다면?
resultMap
태그- DAO에서 불러올 때는
List<BoardVO> list = session.selectList("board.BoardDAO.selectAllMap");
로 불러온다.
<resultMap type="boardVO" id="boardMap">
<result column="view_cnt" property="viewCnt"/>
<result column="reg_date" property="regDate"/>
</resultMap>
<select id="selectAllMap" resultMap="boardMap">
<!-- select no, title, writer, content, view_cnt, to_char(reg_date,'yyyy-mm-dd') as reg_date -->
select no, title, writer, content, view_cnt , reg_date
from t_board
order by no desc
</select>
board.xml
- common.db패키지 생성 후 board.xml 파일 생성 (mapper파일을 관리하는 패키지)
- sql문 뒤에
;
는 쓰지 않는다.
<?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="board.BoardDAO">
<!-- kr.ac.kopo 생략된것. -->
<insert id="newBoard">
insert into t_board(no, title, writer, content)
values(seq_tboard_no.nextval, 'mybatis연습', 'hong', 'insert')
</insert>
</mapper>
- mybatis-config.xml 파일 mapper 태그 수정
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties" />
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="common/db/board.xml"/>
</mappers>
</configuration>
DAO객체
- SqlSession객체가 있는 곳
1. BoardDAO.java에서 insert 실행
package kr.ac.kopo.board;
import org.apache.ibatis.session.SqlSession;
import kr.ac.kopo.MyConfig;
public class BoardDAO {
private SqlSession session;
public BoardDAO() {
// MyConfig객체로 DB접근
session = new MyConfig().getInstance();
System.out.println(session);
}
public void work() {
insert();
}
private void insert() {
BoardVO vo = new BoardVO();
vo.setTitle("객체로 삽입");
vo.setWriter("홍길동");
vo.setContent("삽입왜안돼 ㅠ");
// "namespace.id"형식으로 작성
session.insert("board.BoardDAO.newBoard", vo);
// commit필요
session.commit();
System.out.println("삽입완료");
}
}
2. BoardDAO.java에서 selectAll 실행
- board.xml에 추가
- resultType을 boardVO로 해주었기 때문에 알아서 VO객체로 받아옴.
session.selectList()
알아서 List형태로 가져옴
<select id="selectAll" resultType="boardVO">
select *
from t_board
order by no desc
</select>
- BoardDAO.java 수정
public void work() {
//insert();
selectAll();
}
private void selectAll() {
//board.xml파일에서 return타입설정해줬기 때문에 자동으로 형변환 됨.
List<BoardVO> list = session.selectList("board.BoardDAO.selectAll");
for(BoardVO board:list) {
System.out.println(board);
}
}
3. BoardDAO.java에서 selectOne 실행
- 하나의 데이터( ex. 번호로 조회 )를 가져오기 위해서는 List를 쓸 필요 없음.
session.selectOne();
는 알아서 Object객체로 가져옴
3-1. 파라미터 타입이 VO 일때
- mapper파일
- parameterType이 VO일때는 변수에 맞는 이름을 작성 :
#{no}
- parameterType이 VO일때는 변수에 맞는 이름을 작성 :
<select id="selectOne" resultMap="boardMap" parameterType="boardVO">
select no, title, writer, view_cnt, to_char(reg_date,'yyyy-mm-dd') reg_date
from t_board
where no = #{no}
</select>
- DAO
private void selectOne() {
BoardVO vo = new BoardVO();
vo.setNo(42);
BoardVO board = session.selectOne("board.BoardDAO.selectOne", vo);
System.out.println(board);
}
3-2. 파라미터 타입이 int 일때
- mapper파일
<select id="selectOne2" resultMap="boardMap" parameterType="int">
<!-- int타입일때는 무엇을 쓰든 상관 없음 -->
select no, title, writer, view_cnt, to_char(reg_date,'yyyy-mm-dd') reg_date
from t_board
where no = #{no}
</select>
- DAO
private void selectOne2() {
BoardVO board = session.selectOne("board.BoardDAO.selectOne2", 42);
System.out.println(board);
}
3-3. 중복되는 코드 묶기
<sql>
태그와<include>
를 이용하여 중복되는 코드를 묶을 수 있다.- selectOne과 selectAll에서 중복되는 공통의 쿼리를 묶어주는 역할
<sql id="selectBoard">
select no, title, writer, view_cnt, to_char(reg_date,'yyyy-mm-dd') reg_date
from t_board
</sql>
<select id="selectOne3" resultMap="boardMap" parameterType="int">
<include refid="selectBoard"/>
where no = #{no}
</select>
동적으로 수행하기01 where in
- 제목으로 검색, 작성자로 검색 기능을 구현할 때 sql에서 바뀌는 부분은 where절만 달라지게 됨
- where title= ? 또는 where writer= ?
- 조건에 따라 다른 쿼리를 작동하게 하는 것 : 동적태그
- 태그
<foreach>
: where addr in (‘seoul’,’busan’,’jeju’)의 동작이 가능하게 해줌<foreach item="addr" open="(" seperator="," close=")" collection="addrs"></foreach>
- collection
- item
- open : 첫 시작을 괄호로 설정가능
- separator : 구분자
- close : (괄호) 닫기
<if>
<choose>
<where>
<where> <if test="writer != null"> writer like #{writer} </if> </where>
- 다른 조건에 AND가 붙어있어도 where을 사용하면 알아서 생략해준다
<set>
1. BoardVO의 int[] 멤버변수로 넘기기
- mapper파일
<select id="selectNos" resultMap="boardMap" >
<include refid="selectBoard" />
where no in
<foreach collection="nos" item="bno" open="(" separator="," close=")">
#{bno}
</foreach>
order by no
</select>
- DAO
private void selectNos() {
BoardVO vo = new BoardVO();
vo.setNos(new int[] {1,2,4,7,11,15,18,20,21});
/*
* select * from t_board where no in(1,2,4,7,11,15,18,20,21);
*/
List<BoardVO> list = session.selectList("board.BoardDAO.selectNos", vo);
for(BoardVO b:list) {
System.out.println(b);
}
}
2. List로 넘기기
- mapper파일
<select id="selectNos2" resultMap="boardMap" parameterType="java.util.List">
<!-- parameterType="list, map" 가능 -->
<include refid="selectBoard" />
where no in
<foreach collection="list" item="bno" open="(" separator="," close=")">
#{bno}
</foreach>
order by no
</select>
- DAO
private void selectNos2() {
/*
* select * from t_board where no in(1,2,4,7,11,15,18,20,21);
*/
List<Integer> nos = new ArrayList<>();
nos.add(1);
nos.add(2);
nos.add(3);
nos.add(4);
nos.add(5);
List<BoardVO> list = session.selectList("board.BoardDAO.selectNos2", nos);
for(BoardVO b:list) {
System.out.println(b);
}
}
3. 배열로 넘기기
- mapper 파일
<select id="selectNos3" resultMap="boardMap" parameterType="array">
<include refid="selectBoard" />
where no in
<foreach collection="list" item="bno" open="(" separator="," close=")">
#{bno}
</foreach>
order by no
</select>
- DAO
private void selectNos3() {
/*
* select * from t_board where no in(1,2,4,7,11,15,18,20,21);
*/
int[] nos = new int[] {1,2,3,4,5,6,7};
List<BoardVO> list = session.selectList("board.BoardDAO.selectNos3", nos);
for(BoardVO b:list) {
System.out.println(b);
}
}
동적으로 수행하기02 like
- 제목으로 찾기할 때 “파일”이라는 단어가 들어간 게시글을 찾고 싶을 때
- ‘파일%’
- mapper파일
- like를 사용하려면 preparedStatement객체(#{title})가 아닌 Statement객체로 표현해야함.
- PreparedStatement :
#
- Statement :
$
<select id="selectWhere" parameterType="string">
<include refid="selectBoard" />
<!-- like를 사용하려면 preparedStatement객체(#{title})가 아닌 Statement객체로 표현해야함.
문자열이므로 ' '를 붙여주었음 -->
where title like '${title}%'
</select>
제목과 작성자로 찾기 (like)
- 조건에 따라 불니하고 싶을 때 where, if 태그 사용
<select id="selectWhere2" parameterType="boardVO" resultMap="boardMap">
<include refid="selectBoard" />
<where>
<if test="title != null">
title like '${title}%'
</if>
<if test="writer != null">
and writer=#{writer}
</if>
</where>
</select>
- DAO
private void selectWhere2() {
BoardVO vo = new BoardVO();
//vo.setTitle("객체로 삽입");
vo.setWriter("홍길동");
List<BoardVO> list = session.selectList("board.BoardDAO.selectWhere2",vo);
for(BoardVO board :list) {
System.out.println(board);
}
}