[꼼꼼한 개발자] 꼼코더
30. 코드로 배우는 스프링 웹 프로젝트 - [스프링 MVC 프로젝트의 기본 구성] - 영속 영역의 CRUD 구현 본문
30. 코드로 배우는 스프링 웹 프로젝트 - [스프링 MVC 프로젝트의 기본 구성] - 영속 영역의 CRUD 구현
꼼코더 2023. 1. 9. 00:04✅ 영속 영역의 CRUD 구현
영속 영역은 웹 프로젝트 구조에서 마지막 영역이지만
실제로 구현시 가장 먼저 할 수 있는 영역이기도 한다.
영속 영역은 기본적으로 CRUD 작업을 하기 때문에 테이블과 VO(DTO) 등 약간의 준비만으로도
비즈니스 로직과 무관하게 CRUD 작업을 작성할 수 있다.
MyBatis는 내부적으로 JDBC의 PreparedStatement를 활용한다
파라미터를 처리하는 ‘?’에 대한 치환은 ‘#{속성}’을 이용해서 처리한다.
💡영속성(persistency)이란?
데이터를 영구적으로 저장하는 것을 의미.
따라서 영속성 컨텍스트란 직역 하자면 데이터를 영구적으로 저장하는 환경 정도로 해석될 수 있다.
📸 create(intsert) 처리
tbl_board 테이블은 PK칼럼으로 bno를 지정했다.
시퀀스를 이용해서 데이터가 추가될 때마다 자동으로 번호가 만들어지는 방식을 사용했다.
이처럼 자동으로 PK 값이 정해지는 경우는 2가지 방식으로 처리할 수 있다.
- insert문이 실행되고 생성된 PK 값을 알 필요가 없는 경우
- insert문이 실행되고 생성된 PK 값을 알아야 하는 경우
BoardMapper 인터페이스는 위 상황들을 고려해 다음과 같이 메서드 추가를 선언한다.
👨🏻💻 BoardMapper 인터페이스, BoardMapper.XML 추가
BoardMapper의 insert()는 시퀀스의 다음 값을 구하여 insert 할 때 사용한다.
insert문은 몇 건의 데이터가 변경되었지만을 알려주기 때문에 추가된 데이터의 PK 값을 알 수는 없지만
1번의 SQL 처리만으로 작업이 완료되는 장점이 있다.
insertSelectKey()는 @SelectKey라는 MyBatis의 어노테이션을 이용한다.
- @SelectKey 주로 PK 값을 미리(before) SQL로 처리해 두고 특정한 이름으로 결과를 보관하는 방식.
@Insert 시 SQL문을 보면 #{bno}와 같이 이미 처리된 결과를 이용하는 것을 볼 수 있다.
👨🏻💻 테스트 코드 수정(BoardMappertest)
코드에 새로운 메소드를 작성한다.
마지막 줄 log.info(board)의 작성이유는
Lombok이 만들어주는 toString()을 이용해서 bno 멤버 변수(인스턴스 변수)의 값을 알아보기 위함이다.
💁🏻♂️ 결과
마지막 결과를 보면 BoardVO 클래스의 toString()의 결과가 출력된다.
보면 bno의 값이 null로 비어 있는것을 확인할 수 있다.
👨🏻💻 @SelectKey를 이용(BoardMappertest 코드 작성)
💁🏻♂️ testInsertSelectKey()의 결과
결과를 보면 ‘select seq_board.nextval from dual’과 같은 쿼리가 먼저 실행되고
여기서 생성된 결과를 이용해 bno 값으로 처리되는 것을 볼 수 있다.
BoardMapper의 InsertSelectKey()의 @Insert 문의 SQL을 보면
아래와 같이 파라미터로 전달되는 BoardVO의 bno 값을 사용하게 되어있다.
insert into tbl_board (bno, title, content, writer)
values (#{bno}, #{title}, #{content}, #{writer})
테스트 코드의 마지막 부분을 보면 BoardVO 객체의 bno 값이 이전과 달리 지정된 것을 볼 수 있다.
그 이유는 시퀀스의 값이므로 현재 테스트 하는 환경마다 다른 값이 나온다.
시퀀스 값은 중복 없는 값을 위한 것일 뿐 다른 의미가 없다
@SelectKey를 이용하는 방식은 SQL을 한 번 더 실행하는 부담이 있기는 하지만
자동으로 추가되는 PK값을 확인해야 하는 상황에서 유용하게 사용된다.
🔍 read(select) 처리
insert가 된 데이터를 조회하는 작업은 PK를 이용해서 처리하므로
BoardMapper의 파라미터 역시 BoardVO 클래스의 bno 타입 정보를 이용해서 처리한다.
👨🏻💻 BoardMapper 인터페이스 , BoardMapper.XML 추가
MyBatis는 Mapper 인터페이스의 리턴 타입에 맞게 select의 결과를 처리하기 때문에
tbl_board의 모든 칼럼은 BoardVO의
‘bno, title, content, writer, regdate, updateDate’ 속성값으로 처리된다.
MyBatis는 bno라는 칼럼이 존재하면 인스턴스의 ‘setBno()’를 호출하게 된다.
MyBatis의 모든 파라미터와 리턴 타입의 처리는 get 파라미터명(), set칼럼명()의 규칙으로 호출된다.
다만 위와 같이 #{속성}이 1개만 존재하면 별도의 get 파라미터명()을 사용하지 않고 처리된다.
👨🏻💻 BoardMappertest 코드 작성
mapper.read()를 호출할 경우에는 현재 테이블에 있는 데이터의 bno 값의 여부를 반드시 확인해야 한다.
(bno 3번이 있는걸 로그로 확인 후 read의 속성값으로 넣어줬다)
💁🏻♂️ 결과
현재 테이블에 존재하는 데이터의 bno 칼럼의 값을 이용해서 테스트 코드를 확인해 보자.
❎ delete 처리
데이터 삭제 작업 역시 PK 값을 이용해서 처리한다.
조회하는 작업과 유사하게 처리한다.
등록, 삭제, 수정과 같은 DML 작업은 ‘몇 건의 데이터가 삭제 or수정되었는지’를 반환할 수 있다.
👨🏻💻 BoardMapper 인터페이스, BoardMapper.XML 추가
delete()의 메서드 리턴 타입은 int로 지정해서 만일 정상적으로 데이터가 삭제되면
1 이상의 값을 가지도록 작성한다.
👨🏻💻BoardMappertest 테스트 코드 작성
현재 테이블에 존재하는 번호의 데이터를 삭제해 보고 ‘1’이라는 값이 출력되는지 확인
만역 해당 번호의 게시물이 없다면 ‘0’이 출력된다.
💁🏻♂️ 결과
testDelete()의 경우 3번 데이터가 존재했다면 다음과 같은 결과가 출력된다.
✍🏻 update 처리
게시물의 업데이트는 제목, 내용, 작성자를 수정한다고 가정한다.
업데이트 시 최종 수정시간을 데이터베이스 내 현재 시간으로 수정한다.
Update는 detele와 마찬가지로 ‘몇 개의 데이터가 수정되었는가’를 처리할 수 있게
int 타입으로 메서드를 설계한다.
👨🏻💻 BoardMapper 인터페이스, BoardMapper.XML 추가
SQL에서 중요한 부분은 2가지이다.
- update 최종 수정시간의 칼럼이 현재시간으로 변경해 주고 있다는 점’
- ‘regdate 칼럼은 최초 생성 시간이므로 건드리지 않는다는 점’
#{title}은 파라미터로 전달된 BoardVO 객체의 getTitle()과 같은 메서드들을 호출해서 파라미터들이 처리된다.
👨🏻💻BoardMappertest 테스트 코드 작성
테스트 코드는 read()를 이용해서 가져온 BoardVO 객체의 일부를 수정하는 방식이나
직접 BoardVO 객체를 생성해서 처리할 수 있다.
예제는 객체를 생성해서 테스트를 진행한다.
💁🏻♂️ 결과
27번째 글이 존재한다면 나오는 결과이다.
🧹 최종 정리
- 영속 영역은 웹 프로젝트 구조에서 마지막 영역이지만 실제로 가장 먼저 구현할 수 있는 영역이기도 한다.
- 영속 영역은 기본적으로 CRUD 작업을 하기 때문에 테이블과 VO(DTO) 등 약간의 준비만으로도 비즈니스 로직과 무관하게 CRUD 작업을 작성할 수 있다.
- @SelectKey를 이용하는 방식은 SQL을 한 번 더 실행하는 부담이 있기는 하지만 자동으로 추가되는 PK값을 확인해야 하는 상황에서 유용하게 사용된다.
- update SQL에서 중요한 부분은 2가지이다.
- 최종 수정 시간 칼럼을 현재시간으로 변경한다.
- 최초 생성 시간 칼럼은 이므로 건드리지 않는다
위 내용은 코드로 배우는 스프링 웹 프로젝트 교재를 참고하여 작성되었습니다.