인프런 커뮤니티 질문&답변

양치잘하기님의 프로필 이미지

작성한 질문수

스프링 DB 2편 - 데이터 접근 활용 기술

JdbcTemplate - 이름 지정 파라미터 2

update에서 new BeanPropertySqlParameterSource()사용시 문제

해결된 질문

작성

·

181

0

강의에서 update부분을

new BeanPropertySqlParameterSource()

로 변경해서 사용해 보았는데 수정이 정상적을 이루어 졌습니다.

I’d가 어떻게 자동으로 매핑이 되는건가요?

답변 1

0

안녕하세요. 양치잘하기님, 공식 서포터즈 OMG입니다.

강의 코드를 변경하셨다면 어떻게 변경했는지 알아야 확인 후 답변을 드릴 수 있습니다 😀

MapSqlParameterSource() 대신 BeanPropertySqlParameterSource()를 사용한게 맞을까요? 파라미터로 받아오는 itemId와 sql 처리가 어떻게 되었는지 등 전반적인 update()코드와 관련된 클래스 중 강의와 다르게 직접 작성한 코드가 있다면 같이 첨부해주시겠어요?

image

감사합니다.

@Slf4j
public class JdbcTemplateItemRepositoryV2 implements ItemRepository {
//    private final JdbcTemplate template;
    private final NamedParameterJdbcTemplate template; // 파라미터 바인딩을 순서가 아닌 이름으로 하게 해줌
    public JdbcTemplateItemRepositoryV2(DataSource dataSource) {
        this.template = new NamedParameterJdbcTemplate(dataSource);
    }

    @Override
    public Item save(Item item) {
        String sql = "insert into item(item_name, price, quantity) " +
                "values (:item_name, :price, :quantity)";

        // 이름기반의 파라미터가 필요
        // item객체의 필드들을 이름으로 파라미터를 만든다
//        SqlParameterSource param = new BeanPropertySqlParameterSource(item);
        Map<String, Object> param = Map.of(
                "item", item.getItemName(),
                "price", item.getPrice(),
                 "quantity", item.getQuantity()
        );
        KeyHolder keyHolder = new GeneratedKeyHolder();
        template.update(sql, (SqlParameterSource) param, keyHolder);

        long key = keyHolder.getKey().longValue();
        item.setId(key);
        return item;
    }

    @Override
    public void update(Long itemId, ItemUpdateDto updateParam) {
        String sql = "update item set item_name = :item_name, price = :price, quantity = :quantity where id = :id";

//        SqlParameterSource param = new MapSqlParameterSource()
//                .addValue("itemName", updateParam.getItemName())
//                .addValue("price", updateParam.getPrice())
//                .addValue("quantity", updateParam.getQuantity())
//                .addValue("id", itemId);
        SqlParameterSource param = new BeanPropertySqlParameterSource(updateParam);


        template.update(sql, param);
    }

    @Override
    public Optional<Item> findById(Long id) {
        String sql = "select id, item_name, price, quantity from item where id = :id";
        try {
            Map<String, Object> param = Map.of("id", id);
//            SqlParameterSource param = new BeanPropertySqlParameterSource(id);
            Item item = template.queryForObject(sql, param, itemRowMapper());
            return Optional.of(item);
        } catch (EmptyResultDataAccessException e) {
            return Optional.empty();
        }
    }

    @Override
    public List<Item> findAll(ItemSearchCond cond) {
        Integer maxPrice = cond.getMaxPrice();
        String itemName = cond.getItemName();
        SqlParameterSource param = new BeanPropertySqlParameterSource(cond);
        String sql = "select id, item_name, price, quantity from item";
        //동적 쿼리
        if (StringUtils.hasText(itemName) || maxPrice != null) {
            sql += " where";
        }
        boolean andFlag = false;
        if (StringUtils.hasText(itemName)) {
            sql += " item_name like concat('%',:itemName,'%')";
            andFlag = true;
        }
        if (maxPrice != null) {
            if (andFlag) {
                sql += " and";
            }
            sql += " price <= :maxPrice";
        } log.info("sql={}", sql);
        return template.query(sql, param, itemRowMapper());
    }
    private RowMapper<Item> itemRowMapper() {

//        return (rs, rowNum) -> {
//            Item item = new Item();
//            item.setId(rs.getLong("id"));
//            item.setItemName(rs.getString("item_name"));
//            item.setPrice(rs.getInt("price"));
//            item.setQuantity(rs.getInt("quantity"));
//            return item;
//        };
        return BeanPropertyRowMapper.newInstance(Item.class); //camel 변환 지원
    }
}

해당 코드를 실행하였습니다.

첫 실행시 아이템 이름을 수정하니

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Mon May 13 13:24:51 KST 2024

There was an unexpected error (type=Internal Server Error, status=500).

로 이동하여 수정이 안되는데 같은 아이템의 가격, 수량을 수정하는것은 정상적으로 동작합니다.

1, 2번 아이템이 특히 이렇게 동작하였고 나머지 아이템들은 이름, 가격, 수량을 수정하여도 정상적으로 반영이 됩니다.

 

아 제가 Config에 빈 등록할때 리포지토리를 V2로 안바꾸고 실행해서 적용이 안되었던거였네요 ;;; ㅎㅎV2로 변경하고 나니 오류 발생합니다.

그런데 강의자료로 올려주신pdf에는 V2에 @Repository어노테이션에 붙어있는데

개발자가 직접 빈 등록을 하였으면 @Repository 어노테이션이 필요 없는것 아닌가요? 영상에서는 안 붙여 주셨는데 강의자료에 따로 붙어있는 이유가 있나요?

그리고 h2데이터베이스 클라이언트에서 item테이블의 튜플들을 모두 지우고 서버를 다시 시작했는데 id가 1번부터 시작하지 않고 지우기전 id의 다음순서의 id로 시작을 하는데 id는 왜 1번부터 시작하지 않는건가요? 1번부터 시작하게 하려면 어떻게 해야하나요?

예리한 질문이십니다 😀

@Repository를 사용하면 JDBC 예외를 스프링의 데이터 계층 예외로 변환해주는 AOP가 적용되는데요, JdbcTemplate은 JDBC 예외를 스프링의 데이터 계층 예외로 변환해주는 기능을 내부에 포함하고 있어서 사용하지 않았다고 하시네요.

메뉴얼과의 차이는 잘 모르겠습니다.

https://www.inflearn.com/questions/1211018/repository-%EC%82%AC%EC%9A%A9-%EC%B0%A8%EC%9D%B4%EC%A0%90

h2 시퀀스를 초기화 하는 방법은 다음 링크를 참고해주세요^^

https://blog.naver.com/ddalki333/222329392139