4. Spring create(insert) 처리
MyBatis는 내부적으로 JDBC의 PreparedStatement를 활용한 파라미터를 처리하는 '?'에 대한 치환은 #{속성}을 이용해서 처리한다.
예시
<?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">
<!-- association : 1:N에서 N쪽의 정보를 조회할 때 1쪽의 정보도 함께 읽을 것임 -->
<mapper namespace="www.study.com.bullutineBoard.mapper.PostMapper">
<resultMap id="boardResultMap"
type="www.study.com.bullutineBoard.model.BoardVO">
<id property="id" column="id" />
<result property="name" column="name" />
</resultMap>
<resultMap id="replyResultMap"
type="www.study.com.bullutineBoard.model.ReplyVO">
<id property="hierarchyId" column="hierarchy_id" />
<result property="content" column="content" />
<!-- 다른 Mapper.xml에서 정의된 resultMap을 활용하는 방법 -->
<association property="writer" columnPrefix="m_" resultMap="www.study.com.party.mapper.PartyMapper.partyResultMap"/>
<!-- 구분자 -->
<discriminator javaType="String" column="post_type">
<case value="POST" resultMap="postResultMap" />
</discriminator>
</resultMap>
<resultMap id="postResultMap"
type="www.study.com.bullutineBoard.model.PostVO" extends="replyResultMap">
<result property="title" column="title" />
<association property="board" columnPrefix="b_" resultMap="boardResultMap"/>
</resultMap>
<select id="getAll" resultMap="replyResultMap">
select p.*, m.id m_id, m.name m_name, m.birth_date m_birth_date, m.party_type m_party_type, m.gender m_gender, m.sales_tot m_sales_tot
from t_post p
left outer join t_party m on p.writer_id = m.id
</select>
<!-- Composite Pattern에 따른 개발 방법 -->
<select id="getAllReply" resultMap="replyResultMap">
select p.*, m.id m_id, m.name m_name, m.birth_date m_birth_date, m.party_type m_party_type, m.gender m_gender, m.sales_tot m_sales_tot
from t_post p
left outer join t_party m on p.writer_id = m.id
where hierarchy_id like '1%'
</select>
<insert id="insertPost">
<selectKey keyProperty="hierarchyId" order="BEFORE" resultType="String">
select to62(seq4post.nextval) from dual
</selectKey>
insert into t_post (hierarchy_id, bb_id, writer_id, post_type, title, content)
values(#{hierarchyId}, #{board.id}, #{writer.id}, 'POST', #{title}, #{content})
</insert>
<insert id="insertReply">
<selectKey keyProperty="hierarchyId" order="BEFORE" resultType="String">
select #{parent.hierarchyId} || #{hidDeli} || to62(seq4post.nextval) from dual
</selectKey>
insert into t_post(hierarchy_id, writer_id, content)
values(#{hierarchyId}, #{writer.id}, #{content})
</insert>
</mapper>
tbl_board 테이블은 PK 칼럼으로 bno를 이용하고 시퀀스를 이용해서 자동으로 데이터가 추가될 때 번호가 만들어지는 방식을 사용. 이처럼 자동으로 PK 값이 정해지는 경우에는 다음과 같은 2가지 방식으로 처리할 수 있다.
- insert만 처리되고 생성된 PK값을 알 필요가 없는 경우
- insert문이 실행되고 생성된 PK값을 알아야 하는 경우
org.zerock.mapper.BoardMapper인터페이스
1. public void insert(BoardVO board);
2. public void insertSelectKey(BoardVO board); 추가 작성
package org.zerock.mapper;
import java.util.List;
import org.zerock.domain.BoardVO;
import org.apache.ibatis.annotations.Select;
public interface BoardMapper {
// @Select("select * from tbl_board where bno > 0") //전체 리스트를 가지고 온다. 2.setter 주석처리
public List<BoardVO> getList();
public void insert(BoardVO board);
public void insertSelectKey(BoardVO board);
}
BoardMapper.xml 추가 작성
<!-- public void insert(BoardVO board);
public void insertSelectKey(BoardVO board);-->
1. <insert id="insert">
insert into tbl_board (bno, title, content, writer)
values(seq_board.nextval, #{title}, #{content}, #{writer})
</insert>
2. <insert id="insertSelectKey">
<selectKey keyProperty="bno" order="BEFORE" resultType="long">
select seq_board.nextval from dual </selectKey>
insert into tbl_board (bno, title, content, writer)
values(#{bno}, #{title}, #{content}, #{writer})
</insert>
</mapper>
<?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">
<!--
package org.zerock.mapper;
@Select("select * from tbl_board where bno > 0") //전체 리스트를 가지고 온다.
public List<BoardVO> getList();
}
package org.zerock.domain;
public class BoardVO;
private Long bno; //BNO NUMBER(10,0)
private String title; //TITLE VARCHAR2(200 BYTE)
private String content; //CONTENT VARCHAR2(2000 BYTE)
private String writer; //WRITER VARCHAR2(50 BYTE)
private Date regdate; //REGDATE DATE
private Date updateDate; //UPDATEDATE DATE -->
<mapper namespace="org.zerock.mapper.BoardMapper"> <!-- board mapper 주소 -->
<select id="getList" resultType="org.zerock.domain.BoardVO"> <!-- mapper의 함수명 / vo경로 -->
<![CDATA[
select * from tbl_board where bno > 0
]]>
</select>
<!-- public void insert(BoardVO board);
public void insertSelectKey(BoardVO board);-->
<insert id="insert">
insert into tbl_board (bno, title, content, writer)
values(seq_board.nextval, #{title}, #{content}, #{writer})
</insert>
<insert id="insertSelectKey">
<selectKey keyProperty="bno" order="BEFORE" resultType="long">
select seq_board.nextval from dual </selectKey>
insert into tbl_board (bno, title, content, writer)
values(#{bno}, #{title}, #{content}, #{writer})
</insert>
</mapper>
BoardMapperTests 클래스 일부 작성
@Test
public void testInsert() {
BoardVO board = new BoardVO();
board.setTitle("새로 작성하는 글");
board.setContent("새로 작성하는 내용");
board.setWriter("newbie");
mapper.insert(board);
log.info(board);
}
테스트 결과
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@7085bdee, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@1ce92674, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@5700d6b1, org.springframework.test.context.support.DirtiesContextTestExecutionListener@6fd02e5, org.springframework.test.context.transaction.TransactionalTestExecutionListener@5bcab519, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@e45f292]
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from URL [file:src/main/webapp/WEB-INF/spring/root-context.xml]
INFO : org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@3dd4520b: startup date [Tue Sep 08 18:23:23 KST 2020]; root of context hierarchy
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=2, title=테스트 제목, content=테스트 내용, writer=user00, regdate=Wed Aug 26 22:14:28 KST 2020, updateDate=Wed Aug 26 22:14:28 KST 2020)
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=3, title=테스트 제목, content=테스트 내용, writer=user00, regdate=Wed Aug 26 22:14:29 KST 2020, updateDate=Wed Aug 26 22:14:29 KST 2020)
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=4, title=테스트 제목, content=테스트 내용, writer=user00, regdate=Wed Aug 26 22:14:30 KST 2020, updateDate=Wed Aug 26 22:14:30 KST 2020)
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=5, title=테스트 제목, content=테스트 내용, writer=user00, regdate=Wed Aug 26 22:14:32 KST 2020, updateDate=Wed Aug 26 22:14:32 KST 2020)
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=6, title=테스트 제목, content=테스트 내용, writer=user00, regdate=Wed Aug 26 22:14:32 KST 2020, updateDate=Wed Aug 26 22:14:32 KST 2020)
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=null, title=새로 작성하는 글, content=새로 작성하는 내용, writer=newbie, regdate=null, updateDate=null)
INFO : org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@3dd4520b: startup date [Tue Sep 08 18:23:23 KST 2020]; root of context hierarchy
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
@SelectKey를 이용한 경우
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=23, title=새로 작성하는 글, content=새로 작성하는 내용, writer=newbie, regdate=Tue Sep 08 18:23:24 KST 2020, updateDate=Tue Sep 08 18:23:24 KST 2020)
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=null, title=새로 작성하는 글 select key, content=새로 작성하는 내용 select key, writer=newbie, regdate=null, updateDate=null)
INFO : org.zerock.mapper.BoardMapperTests - BoardVO(bno=null, title=새로 작성하는 글, content=새로 작성하는 내용, writer=newbie, regdate=null, updateDate=null)
INFO : org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@3dd4520b: startup date [Tue Sep 08 18:31:51 KST 2020]; root of context hierarchy
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
select seq_board.nextval from dual과 같은 쿼리가 먼저 실행되고 여기서 생성된 결과를 이용해 bno 값으로 처리 되는 것을 볼 수 있다.