Spring | 08 영속/비즈니스 계층의 CRUD 구현

파과·2022년 9월 21일

테스트 코드는 생략했습니다.

영속 계층의 구현 준비

VO 클래스 작성

VO클래스는 테이블 설계를 기준으로 작성한다.

org.zerock.domain 패키지에 작성하자.

package org.zerock.domain;

import java.util.Date;

import lombok.Data;

@Data
public class BoardVO {

	private Long bno;
	private String title;
	private String content;
	private String writer;
	private Date regdate;
	private Date updateDate;
}

@Data 어노테이션을 적용하면 Lombok이 생성자, getter/setter, toString()등을 만들어준다.

Mapper 인터페이스와 Mapper XML

간단한 SQL은 어노테이션 처리가 무난하고, 복잡하고 상황에 따라 다른 SQL의 경우 XML을 이용하는 것이 좋다.

org.zerock.mapper 패키지에 작성한다.
BoardMapper.java 인터페이스

package org.zerock.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.zerock.domain.BoardVO;

public interface BoardMapper {

	@Select("select * from tbl_board where bno > 0")
	public List<BoardVO> getList();
}

SQL developer에서 SQL문을 먼저 실행해 결과를 확인한다.

테스트할 수 있도록 test패키지에 org.zerock.mapper패키지를 작성하고 BoardMapperTests 클래스를 추가한다.

package org.zerock.mapper;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class BoardMapperTests {

	@Setter(onMethod_ = @Autowired)
	private BoardMapper mapper;
	
	@Test
	public void testGetList() {
		mapper.getList().forEach(board -> log.info(board));
	}
}

동일한 결과가 나와야 한다.

이제 src/main/resources 내에 폴더를 만드는데, org - zerock - mapper 순서로 하나씩 만들어야 한다. 만들고 난 후 BoardMapper.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="org.zerock.mapper.BoardMapper">
	<select id="getList" resultType="org.zerock.domain.BoardVO">
		<![CDATA[
		 select * from tbl_board where bno > 0
		]]>
	</select>
</mapper>
  • <mapper>의 namespace 속성값을 Mapper인터페이스와 동일한 값으로 줘야 한다.
  • <select> 태그의 id속성값은 메서드의 이름과 일치하게 작성한다.
  • resultType의 속성값은 select쿼리의 결과를 특정 클래스의 객체로 만들기 위해서 설정한다.
  • CDATA 부분은 XML에서 부등호를 사용하기 위해서 사용한다.

XML에 SQL문을 처리했으니 BoardMapper인터페이스에 SQL을 제거한다. (주석처리한다.)

package org.zerock.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.zerock.domain.BoardVO;

public interface BoardMapper {

	//@Select("select * from tbl_board where bno > 0")
	public List<BoardVO> getList();
}

기존 테스트 코드가 동일하게 동작하는지 확인한다.

BoardMapper.xml의 선언을 <!DOCTYPE mapper>이라고만 하면 오류가 난다. PUBLIC ~~ 까지 적어줘야 한다.

영속 영역의 CRUD 구현

영속persistence 영역은 기본적으로 CRUD작업이다. 테이블과 VO(DTO) 정도 준비만으로 비즈니스 로직과 무관하게 CRUD 작업을 작성할 수 있다.

MyBatis는 내부적으로 JDBC의 PreparedStatement를 활용하고 필요 파라미터를 처리하는 '?'에 대한 치환은 #{속성}을 이용해 처리한다.

CREATE(INSERT)

자동으로 pk값이 정해지는 경우(시퀀스) 다음과 같은 2가지 방식으로 처리할 수 있다.

  • insert만 처리되고 pk값 알 필요 없는 경우
  • insert 실행되고 생성된 pk값 알아야 하는 경우

BoardMapper 인터페이스에 추가

package org.zerock.mapper;

import java.util.List;

//import org.apache.ibatis.annotations.Select;
import org.zerock.domain.BoardVO;

public interface BoardMapper {

	//@Select("select * from tbl_board where bno > 0")
	public List<BoardVO> getList();
	
	public void insert(BoardVO board);
	
	public void insertSelectKey(BoardVO board);
}

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="org.zerock.mapper.BoardMapper">

	<select id="getList" resultType="org.zerock.domain.BoardVO">
		<![CDATA[
		 select * from tbl_board where bno > 0
		]]>
	</select>
	
	<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>

테스트 코드 생략

READ(SELECT)

BoardMapper.java

package org.zerock.mapper;

import java.util.List;

//import org.apache.ibatis.annotations.Select;
import org.zerock.domain.BoardVO;

public interface BoardMapper {

	//@Select("select * from tbl_board where bno > 0")
	public List<BoardVO> getList();
	
	public void insert(BoardVO board);
	
	public void insertSelectKey(BoardVO board);
	
	public BoardVO read(Long bno);
}

BoardMapper.xml 에 추가

<select id="read" resultType="org.zerock.domain.BoardVO">
  select * from tbl_board where bno = #{bno}
</select>

MyBatis는 bno라는 칼럼이 존재하면 인스턴스의 setBno()를 호출한다. MyBatis의 모든 파라미터와 리턴 타입의 처리는 get파라미터명(), set칼럼명() 규칙으로 호출된다. 다만 #{속성}이 1개만 존재하면 별도의 get파라미터명()을 사용하지 않고 처리된다.

DELETE

BoardMapper.java에 추가

public int delete(Long bno);

Boardmapper.xml에 추가

<delete id="delete">
  delete from tbl_board where bno = #{bno}
</delete>

UPDATE

제목, 내용, 작성자 수정.
최종 수정시간을 DB내 현재시간으로 수정한다.
update도 delete와 마찬가지로 몇 개의 데이터가 수정되었는지를 처리할 수 있게 int타입으로 메서드를 설계한다.

public int update(BoardVO board);
<update id="update">
  update tbl_board
  set title = #{title},
  content = #{content},
  writer = #{writer},
  updateDate = sysdate
  where bno = #{bno}
</update>

0개의 댓글