SpringBoot #2.4 JDBC - NamedParameterJdbcTemplate

텐저린티·2023년 6월 30일
0

데브코스

목록 보기
18/41

NamedParameterJdbcTemplate

  • JdbcTemplate을 쓸 때 매번 getter로 값을 가져오고, 넣어주는게 아니라
  • <이름, 값> 쌍으로 된 맵을 이용해서 이름을 지어주고 넣어주면 좋지 않을까?
private final NamedParameterJdbcTemplate jdbcTemplate;

public CustomerNamedParamterJdbcTemplate(NamedParameterJdbcTemplate jdbcTemplate) {
	this.jdbcTemplate = jdbcTemplate;
}

private Map<String, Object> toParamMap(Customer customer) {
    return new HashMap<>() {{
        put("customerId", customer.getCustomerId().toString().getBytes());
        put("name", customer.getName());
        put("email", customer.getEmail());
        put("createdAt", Timestamp.valueOf(customer.getCreateAt()));
        put("lastLoginAt", customer.getLastLoginAt() != null ? Timestamp.valueOf(customer.getLastLoginAt()) : null);
    }};
}

@Override
public Customer insert(Customer customer) {
    var update = jdbcTemplate.update(
            "INSERT INTO customers(customer_id, name, email, created_at) VALUES (UUID_TO_BIN(:customerId), :name, :email, :createdAt)",
            toParamMap(customer)
    );
    if (update != 1) {
        throw new RuntimeException("Nothing was inserted");
    }
    return customer;
}

@Override
public Customer update(Customer customer) {
    var update = jdbcTemplate.update(
            "UPDATE customers SET name = :name, email = :email, last_login_at = :lastLoginAt WHERE customer_id = UUID_TO_BIN(:customerId)",
            toParamMap(customer)
    );
    if (update != 1) {
        throw new RuntimeException("Nothing was updated");
    }
    return customer;
}

@Override
public List<Customer> findAll() {
    return jdbcTemplate.query(SELECT_ALL_SQL, customerRowMapper);
}

@Override
public Optional<Customer> findById(UUID customerId) {
    try {
        return Optional.ofNullable(
                jdbcTemplate.queryForObject(
                        "SELECT * FROM customers WHERE customer_id = UUID_TO_BIN(:customerId)",
                        Collections.singletonMap("customerId", customerId.toString().getBytes()),
                        customerRowMapper
                )
        );
    } catch (EmptyResultDataAccessException e) {
        logger.error("Got empty result", e);
        return Optional.empty();
    }
}

@Override
public Optional<Customer> findByName(String name) {
    try {
        return Optional.ofNullable(
                jdbcTemplate.queryForObject(
                        "SELECT * FROM customers WHERE name = :name",
                        Collections.singletonMap("name", name),
                        customerRowMapper
                )
        );
    } catch (EmptyResultDataAccessException e) {
        logger.error("Got empty result", e);
        return Optional.empty();
    }
}

@Override
public Optional<Customer> findByEmail(String email) {
    try {
        return Optional.ofNullable(
                jdbcTemplate.queryForObject(
                        "SELECT * FROM customers WHERE email = :email",
                        Collections.singletonMap("email", email),
                        customerRowMapper)
        );
    } catch (EmptyResultDataAccessException e) {
        logger.error("Got empty result", e);
        return Optional.empty();
    }
}

@Override
public void deleteAll() {
    jdbcTemplate.getJdbcTemplate().update(DELETE_ALL_SQL, Collections.emptyMap());
}

@Override
public int count() {
    return jdbcTemplate.queryForObject(SELECT_COUNT_ALL, Collections.emptyMap(),Integer.class);
}
  • 이런식으로 공통부분을 따로 추출한 맵을 만들어서 전역으로 사용 가능
  • NamedParameterJdbcTemplate의 query, update 함수는 두 번째 파라미터로 mapper를 요구
  • 이름 - 정보 쌍으로 이뤄진 Map을 전달해주면 됨
    • 만약에 필요한 정보가 없는 경우 (delete 같은 경우)엔 Collections.empty() 를 전달하면 됨
    • 한 개의 정보만 필요한 경우엔 Collections.singletonMap()

테스트

@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}

@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(JdbcTemplate jdbcTemplate) {
    return new NamedParameterJdbcTemplate(jdbcTemplate);
}
  • 테스트 설정 클래스에 저렇게 Bean을 설정해주면 된다.
  • NamedParameterJdbcTemplate은 인자로 DataSource를 받을 수도 있고, JdbcTemplate을 받을 수도 있다
  • 테스트 자체는 JdbcTemplate이랑 동일하다.
profile
개발하고 말테야

0개의 댓글

관련 채용 정보