순서
1. 방향성
2. imageEnroll() Mapper
3. swanEnroll() <selectkey> 적용 [Mapper 단계]
1. 방향성
제일 먼저 이미지 정보 테이블에 삽입 쿼리를 실행하는 Mapper 메서드인 imageEnroll()를 작성했습니다.
보통의 경우 imageEnroll() 메서드를 호출하는 Service 단계의 메서드를 새로 작성했지만, 이번 경우엔 상품 정보 등록 Mapper 메서드를 호출하는 Service 단계의 swanEnroll() 메서드에서 imageEnroll() 메서드를 호출하도록 했습니다.
Service 단계의 swanEnroll() 메서드는 뷰(VIEW)로부터 전달받은 데이터 SwanVO를 활용하여 상품 정보와 이미지 정보를 DB에 등록하는 작업을 하게 했습니다.
필요한 product_id 정보를 얻기 위해 이미지 정보 등록 Mapper 메서드 호출에 앞서 상품 정보 등록 Mapper 메서드를 먼저 호출했고, 해당 메서드에선 상품 정보 삽입 쿼리를 실행하는 동시에 새롭게 부여되는 product_id 칼럼 값을 SwanVO 객체의 product_id 변수에 반환하도록 했습니다.
product_id 값을 반환받기 위해 MyBatis의 <selectkey> 태그를 활용했습니다.
2. imageEnroll() Mapper
먼저 AdminMapper.java 인터페이스에 imageEnroll() 메서드 선언부를 작성합니다.
/* 이미지 등록 */
public void imageEnroll(AttachImageVO vo);
파라미터로 이미지 정보가 담긴 AttachImageVO 클래스를 지정했습니다.
이미지 정보의 경우, SwanVO에서 List 자료구조로 보관되는데, Mapper 단계에서 List에 담겨 있는 이미지 정보(AttachImageVO)들을 한 번에 처리할 수 없습니다.
따라서 Mapper 단계 ImageEnroll() 메서드에선 하나의 이미지 정보를 처리하도록 했고, Service 단계에선 List에 담겨 있는 이미지 정보 요소의 수만큼 for문을 활용하여 ImageEnroll() 메서드를 호출하도록 했습니다.
AdminMapper.xml에 imageEnroll() 메서드가 실행할 쿼리문이 담긴 <insert> 태그를 추가합니다.
<!-- 이미지 등록 -->
<insert id="imageEnroll">
insert into image(product_id, fileName, uploadPath, uuid) values (#{product_id}, #{fileName}, #{uploadPath}, #{uuid})
</insert>
3. swanEnroll() 적용 [Mapper 단계]
Mapper 단계의 swanEnroll() 메서드 수행 후, 등록한 product_id 칼럼 값이 파라미터로 전달된 SwanVO 객체의 product_id 변수에 반환되도록 해주기 위해 AdminMapper.xml 파일의 swanEnroll() 메서드가 수행하는 <insert> 태그에 <selectkey> 태그를 적용했습니다.
<selectkey>
자동 생성 키 칼럼(autoincrement(MySQL), IDENTITY(Oracle))을 지원하지 않는 데이터베이스에서 자동 생성 키 기능과 비슷한 효과를 구현하기 위해 사용하거나, 쿼리에서 수행된 특정 칼럼 값을 반환받기 위해 사용합니다.
swanEnroll() 메서드가 수행하는 <insert> 태그 내부에 아래의 <selectkey> 태그와 태그가 수행할 코드를 추가합니다.
<selectKey resultType="_int" keyProperty="product_id" order="BEFORE">
SELECT MAX(product_id)+1 from product
</selectKey>
해석하면, order의 속성 값이 "BEFORE" 이기 때문에 상품 정보를 등록하는 insert문이 실행되기 전, <selectkey> 태그 내의 쿼리문이 실행되고, 쿼리 문의 결과 값이 keyProperty 속성 값으로 지정한 product_id에 resultType 속성 값으로 지정한 int 타입으로 반환된다는 의미입니다.
<selectkey> 태그 내부의 쿼리문은 product 테이블의 product_id 칼럼 값 중 가장 큰 값인 MAX(product_id)를 가져와서 그 값에 더하기 1을 해준 결과를 반환합니다.
이는 insert 문의 결과로 삽입될 product_id 칼럼의 값이 기존 product_id 값들 중 가장 큰 값에서 +1 된 값이기 때문입니다.
하지만 위의 쿼리문은 에러를 발생시킬 수 있습니다. 왜냐하면 <selectkey> 태그 내부에 작성한 쿼리문은 현재 테이블에 있는 product_id 값 중 가장 큰 값에서 +1을 한 값인데, DB에서 처리하는 자동 생성 키 값과 일치하지 않을 수 있기 때문입니다.
예를 들어 product_id 값이 100인 것이 가장 큰 값이 되었는데, 새로운 상품을 등록하기 전 최근에 등록한 상품을 지운다면, 가장 큰 값은 99가 됩니다. DB의 자동 생성 키 기능으로 인해 다음 생성하는 값은 101인데, 작성한 <selectkey> 태그 내부 쿼리 결과는 100이 되어 일치하지 않습니다.
이를 해결하기 위해 제일 최근에 등록된 칼럼 값을 호출해주는 DB의 기능을 사용했습니다.
<selectKey resultType="_int" keyProperty="product_id" order="AFTER">
SELECT MAX(product_id) from product
</selectKey>
코드를 해석하면, order 속성 값 AFTER로 인해 insert문이 실행된 후 <selectkey> 태그 내의 쿼리문이 실행되며, product 테이블의 product_id 값 중 가장 큰 값을 SwanVO에 있는 product_id 변수에 반환시킨다는 의미입니다.
'😎 STS3 Spring 쇼핑몰' 카테고리의 다른 글
STS3 쇼핑몰 프로젝트[27] 업로드 이미지 정보 등록 - 4(트랜잭션 적용) (0) | 2022.10.02 |
---|---|
STS3 쇼핑몰 프로젝트[27] 업로드 이미지 정보 등록 - 3 (0) | 2022.10.02 |
STS3 쇼핑몰 프로젝트[27] 업로드 이미지 정보 등록 - 1 (0) | 2022.10.01 |
STS3 쇼핑몰 프로젝트[26] 업로드 이미지 삭제 - 2 (0) | 2022.09.30 |
STS3 쇼핑몰 프로젝트[26] 업로드 이미지 삭제 - 1 (0) | 2022.09.30 |