[MyBatis] INSERT 성공 후 생성된 자원의 PK 같이 얻어오기

zl존석동

·

2022. 2. 26. 22:55


쿼리 매퍼인 MyBatis에서도 자원을 생성하면서 동시에 그 정보(Primary Key)를 객체에 얻어와보자


 

 

Servlet + Mybatis + Jsp 를 사용하여 웹 서비스를 만들어볼때는 몰랐는데

 

Spring + MyBatis로  REST API를 만들려다보니까 Mybatis를 사용해 특정 테이블에 자원을 INSERT 하고

 

즉시 그 자원에 대한 정보를 가져와야 하는 상황이 발생하게 되었다.

 

 

 

기본적으로 Mybatis 를 통한 CUD 쿼리의 작업 결과는 정수로 결과의 성공여부를 나타내주는 것 같았다.

 

JPA에서는 객체에다가 영속화해줘서 고민해볼 필요가 없는 문제인데 조회 쿼리를 한번 더 날리고 싶지는 않았고

 

검색하여 본 옛 선배님들의 글들 통해 이를 적용해보았던 내용들을 기록해보았다.

 

 

 

 

문제 상황: 회원가입 API

 

 

    @PostMapping
    public ResponseEntity<ResponseDTO> signUp(
            @Validated(ValidationSequence.class)
            @RequestBody SignUpRequest signUpRequest) {
        Long memberId = memberService.signUp(signUpRequest);
        return ResponseEntity.created(URI.create("/members/" + memberId))
                .body(ResponseDTO.builder()
                        .status(HttpStatus.CREATED).build());
    }

 

 

회원가입의 경우 리소스가 생성되었기 때문에 201 CREATED 를 응답해주고 싶었고

 

규칙에 맞게 Location 헤더에 어떤 자원이 생성되었는지를 명시해주고 싶었다.

 

 

이런 규칙을 지키려다보니 Member 의 ID(PK) 가 필요하게 되었던 것이다.

 

회원 뿐만 아니라 모든 자원들의 POST 에 대해 ID 를 헤더에 리턴해줘야 할 것이기 때문에 가볍게 넘어갈 수 없는 문제였다.

 

 

사실 REST API 라서 발생한 문제인 것 처럼 적어버렸지만 좀 더 현실적인 예시가 더 많을 것 같다.

 

회원이 생성될 때 기본적으로 회원이 가지는 생성되거나 수정되어야 하는 또 다른 자원이 있다던가 하는 등의 상황이 많을 것 같았다. 

 

 

 

문제 해결: 매퍼 수정하기

 

 

    <insert id="signUp" parameterType="Member">
        insert into member (email, nickname, password)
        values (#{email}, #{nickname}, #{password})
        <selectKey keyProperty="memberId" order="AFTER" resultType="long">
            select member_seq.currval as member_id from dual
        </selectKey>
    </insert>

 

selectkey가 쿼리를 통한 작업 전,후에 특정한 키 값을 가져와서 처리할 수 있게끔 해준다.

 

오라클을 사용했기 때문에 INSERT 작업 후 자동으로 증가하는 PK에 대해 시퀀스로부터 가져올 수 있도록 해주었다.

 

 

 

public Long signUp(Member member) {
    session.insert("mapper.MemberMapper.signUp", member);
    return member.getMemberId();
}

  

MemberDAO 클래스에서 DTO 객체에 현재 생성된 자원의 아이디를 얻어올 수 있다.

 

쿼리를 직접 비교해보진 않았지만 당연히 INSERT 후 SELECT 하는 것 보다는 훨씬 효율적일 것이다.

 

 

 

@Override
public Long signUp(SignUpRequest signUpRequest) {
    validDuplicateEmail(signUpRequest.getEmail());
    validDuplicateNickname(signUpRequest.getNickname());
    return memberDAO.signUp(signUpRequest.toEntity());
}

 

Service 클래스에서 이렇게 INSERT 결과를 리턴해주면 맨 위에 있던 컨트롤러 API에서 의도한 응답을 잘 해줄 수 있게 된다. 

 

 

 

검색해보았을 때 다른 여러 방법들이 더 있었던 것 같지만

 

오라클이고 시퀀스를 이미 만들었고 자동 증가 트리거도 적용해두었고 이를 활용하는 상황이기 때문에 위 방법이 가장 직관적이고 적절해보여서 사용했던 것 같다!

 

 

 

 

References

 

 

 

Mybatis, insert in Oracle with sequence id

I have tried with this: <insert id="insertPersonalizacionUsuario" useGeneratedKeys="true" keyProperty="param1.id" keyColumn="id"> INSERT INTO dsk_prop_personali (idpersonalizacion, idusu...

stackoverflow.com

 

'Java' 카테고리의 다른 글

Annotation  (0) 2022.02.20
[java] Reflection  (0) 2022.02.14
[Java] ConcurrentModificationException 해결하기  (0) 2022.02.04
[Java] 올바른 Map Iteration  (0) 2022.01.23
[Java] 예외란 뭘까  (0) 2022.01.10