티스토리 뷰

 

원인

Repository를 테스트할 때 key 값에 null이 저장되어 있어 DB 조회가 불가능한 상황이다.

 

DB

DB의 키(PK) 값은 auto_increment 전략을 사용하고 있다. Application 시점에서는 DB에 값을 저장하더라도 키 값을 알 수가 없다. 이는 테스트 코드에서 DB에 정상적으로 저장됐는지 확인하는 과정에서 문제가 발생한다.

 

Application

jdbcTemplate.update("INSERT INTO Member(login_id, name, password) 
	VALUES(?, ?, ?)",member.getLoginId(), member.getName(), member.getPassword());

JdbcTemplate을 사용하여 DB에 Member 객체를 저장하였다.

 

Test

@Test
void save() throws SQLException {
    Member member = new Member();
    member.setLoginId("아이디");
    member.setName("이름");
    member.setPassword("비밀번호");
    memberRepository.save(member);

    Member findMember = memberRepository.findById(member.getId());
    Assertions.assertThat(member.getLoginId()).isEqualTo(findMember.getLoginId());
    Assertions.assertThat(member.getName()).isEqualTo(findMember.getName());
    Assertions.assertThat(member.getPassword()).isEqualTo(findMember.getPassword());
}

DB에 Member가 정상적으로 저장되는지 테스트하는 코드이다. memberRepository.save() 시점에서 Member 객체가 DB에 저장된다. 하지만 해당 Member 객체는 Application 시점에서는 키 값을 가지고 있지 않다(id == null)

따라서 findById(member.getId()) 시점에서 null을 인자로 넘기기 때문에 에러가 터진다.


해결

위의 문제를 해결하기 위해서 JdbcTemplate를 수정해야 한다.

 

KeyHolder 사용

KeyHolder keyHolder = new GeneratedKeyHolder();

KeyHolder를 통해 DB에 저장된 객체의 id값을 Application으로 가져올 수 있다.

 

JdbcTemplate Insert

 

jdbcTemplate.update(conn -> {
    PreparedStatement stmt = conn.prepareStatement("INSERT INTO Member(login_id, name, password) VALUES(?, ?, ?)", new String[]{"id"});
    stmt.setString(1, member.getLoginId());
    stmt.setString(2, member.getName());
    stmt.setString(3, member.getPassword());
    return stmt;
}, keyHolder);

update 메서드에 람다식을 넘긴다. Connection을 인자로 넘겨 파라미터 바인딩 Statement를 생성한다. 



keyHolder.getKey().longValue();

update를 수행하면 KeyHolder에 DB에 저장된 id 값을 가져올 수 있다. KeyHolder는 Number 타입이다. Application에서 id 타입을 Long으로 설정했기 때문에 타입 변환(longValue())을 해준다.

 

최종 코드

public Member save(Member member) throws SQLException {
    KeyHolder keyHolder = new GeneratedKeyHolder();
    jdbcTemplate.update(conn -> {
        PreparedStatement stmt = conn.prepareStatement("INSERT INTO Member(login_id, name, password) VALUES(?, ?, ?)", new String[]{"id"});
        stmt.setString(1, member.getLoginId());
        stmt.setString(2, member.getName());
        stmt.setString(3, member.getPassword());
        return stmt;
    }, keyHolder);
    member.setId(keyHolder.getKey().longValue());
    return member;
}

결론

수정 전

public Member save(Member member) throws SQLException {
	jdbcTemplate.update("INSERT INTO Member(login_id, name, password) 
    	VALUES(?, ?, ?)",member.getLoginId(), member.getName(), member.getPassword());
    return member;
}

수정 후

public Member save(Member member) throws SQLException {
    KeyHolder keyHolder = new GeneratedKeyHolder();
    jdbcTemplate.update(conn -> {
        PreparedStatement stmt = conn.prepareStatement("INSERT INTO Member(login_id, name, password) VALUES(?, ?, ?)", new String[]{"id"});
        stmt.setString(1, member.getLoginId());
        stmt.setString(2, member.getName());
        stmt.setString(3, member.getPassword());
        return stmt;
    }, keyHolder);
    member.setId(keyHolder.getKey().longValue());
    return member;
}
Total
Today
Yesterday
최근에 올라온 글
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30