코딩항해기

[Spring] JDBCTemplate : KeyHolder 본문

Spring

[Spring] JDBCTemplate : KeyHolder

miniBcake 2024. 10. 28. 16:05

[Spring] 템플릿 패턴 : JDBCTemplate 적용 (DAO 고도화)

템플릿 패턴복잡한 로직, 반복되는 로직을 캡슐화하는 패턴으로 중복되는 코드를 줄이고 유지보수를 편리하게 할 수 있다. GoF 디자인패턴 : 템플릿 패턴알고리즘의 구조를 메서드에 정의하고,

minibcake.tistory.com

 

KeyHolder가 필요한 이유

가게 정보를 가진 Store 테이블과 해당 Store의 영업 정보를 가지고 있는 StoreWork 테이블이 있다. 이 테이블은 부모자식관계로 StoreWork가 Store의 PK를 FK로 갖는 구조다. 
 
가게를 새롭게 만들때 가게 정보와 가게 영업 정보를 모두 입력받아 두 테이블에 데이터를 넣게되는데, 이때 Store에 데이터를 넣는 것까지는 문제가 없지만 StoreWork 데이터를 추가할 때 문제가 발생한다. insert (jdbcTemplate.update())의 반환 값은 데이터 변동 개수이기 때문에 방금 전 추가된 Store의 PK를 알 수 없는 것이다. (PK는 시스템에서 지정해주는 값이기 때문이다.)
 
기존에는 가장 높은 PK넘버를 구해 반환받아 사용했기 때문에 트랜잭션이 필수로 필요하고, 한 가게가 등록 중이라면 다른 가게는 등록할 수 없었다. 이 때 KeyHolder를 사용하면 PK번호를 반환 받을 수 있다.
 
 

KeyHolder 구동

JDBCTemplate에서 제공하는 방식으로 KeyHolder를 사용하면 insert된 데이터를 반환받을 수 있다. KeyHolder는 GeneratedKeyHolder를 통해 구현할 수 있다. 구현한 KeyHolder 객체와 PreparedStatementCreator 객체를 update()파라미터로 넣어 실행하면 KeyHolder에 지정된 데이터가 저장되어 .getKey()를 통해 테이터를 반환 받을 수 있다.
 
 

KeyHolder 문법 

람다식 (JAVA 8이상)

public void insert(final Member member) {
    // 자동 생성된 키 값을 저장하기 위한 홀더 생성
    KeyHolder keyHolder = new GeneratedKeyHolder();
    
    jdbcTemplate.update(connection -> {
        // 쿼리 실행 후 생성된 ID 값을 반환받기 위해 두 번째 파라미터 지정
        PreparedStatement pstmt = connection.prepareStatement(
            "INSERT INTO MEMBER (EMAIL, PASSWORD, NAME, REGDATE) " +
            "VALUES (?, ?, ?, NOW())",
            new String[]{"ID"}  // 자동 생성된 키 컬럼명 지정
        );
        
        // PreparedStatement에 파라미터 값 설정
        pstmt.setString(1, member.getEmail());     // 이메일
        pstmt.setString(2, member.getPassword());  // 비밀번호
        pstmt.setString(3, member.getName());      // 이름
        return pstmt;
    }, keyHolder);
    
    // 생성된 키 값을 가져와서 member 객체에 설정
    member.setId(keyHolder.getKey().longValue());
}

 
익명클래스

public void insert(final Member member) {
   // 자동 생성된 키 값을 저장하기 위한 홀더 생성
   KeyHolder keyHolder = new GeneratedKeyHolder();
   
   jdbcTemplate.update(new PreparedStatementCreator() {
       @Override
       public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
           // 쿼리 실행 후 생성된 ID 값을 반환받기 위해 두 번째 파라미터 지정
           PreparedStatement pstmt = con.prepareStatement(
               "INSERT INTO MEMBER (EMAIL, PASSWORD, NAME, REGDATE) " +
               "VALUES (?, ?, ?, NOW())",
               new String[]{"ID"}  // 자동 생성된 키 컬럼명 지정
           );
           
           // PreparedStatement에 파라미터 값 설정
           pstmt.setString(1, member.getEmail());     // 이메일
           pstmt.setString(2, member.getPassword());  // 비밀번호
           pstmt.setString(3, member.getName());      // 이름
           return pstmt;
       }
   }, keyHolder);
   
   // 생성된 키 값을 가져와서 member 객체에 설정
   Number keyValue = keyHolder.getKey();  // 자동 생성된 키 값 반환
   member.setId(keyValue.longValue());    // Number 타입을 long으로 변환하여 설정
}