상품 조회
이제 상품 관리 애플리케이션이 리스트가 아니라 데이터베이스를 사용하게 되었으므로,
조회 기능도 메모리 리스트를 순회하는 방식이 아니라 SQL을 실행해서 결과를 받아오는 방식으로 바뀌어야 한다.
가장 먼저 구현할 수 있는 조회는 상품 번호(id)를 기준으로 하나의 상품을 조회하는 기능이다.
DatabaseProductRepositoy 코드를 수정해준다.
public Product findById(Long id){
SqlParameterSource namedParameter = new MapSqlParameterSource("id", id);
Product product = namedParameterJdbcTemplate.queryForObject(
"SELECT id, name, price, amount FROM products WHERE id = :id",
namedParameter,
new BeanPropertyRowMapper<>(Product.class)
);
return product;
}
여기서 중요한 포인트는 세 가지다.
첫 번째는 MapSqlParameterSource다.
이 객체는 "id"라는 이름에 뒤의 id 값을 연결해주는 역할을 한다.
즉, SQL 안에 있는 :id 자리에 실제 파라미터 값을 매핑하는 것이다.
문자열을 직접 이어붙이는 방식보다 훨씬 안전하고, 가독성도 좋다.
두 번째는 queryForObject()다.
이 메서드는 “결과가 하나일 것”을 기대할 때 사용하는 조회 메서드다.
즉, 상품 번호처럼 고유한 값을 기준으로 단건 조회를 할 때 적합하다.
세 번째는 BeanPropertyRowMapper<>(Product.class)다.
이 부분은 SQL 조회 결과를 Product 객체로 바꿔주는 역할을 한다.
예를 들어 SELECT 결과에서 id, name, price, amount 컬럼이 나오면, 이 값을 Product 클래스의 필드에 대응시켜 넣어준다.
여기서 알아둘 점은 BeanPropertyRowMapper가 Product를 만들 때,
아무 파라미터도 받지 않는 기본 생성자로 객체를 먼저 생성한 뒤, 각 필드를 setter를 통해 채운다는 것이다.
그래서 Product 클래스에는 다음과 같은 setter 메서드가 필요하다.
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setPrice(Integer price) {
this.price = price;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
전체 상품 조회와 이름 포함 검색
전체 조회 코드는 다음과 같이 작성할 수 있다.
public List<Product> findAll(){
List<Product> products = namedParameterJdbcTemplate.query(
"SELECT * FROM products",
new BeanPropertyRowMapper<>(Product.class)
);
return products;
}
이 코드는 products 테이블의 모든 행을 조회해서 List<Product>로 반환한다.
단건 조회와 다른 점은 queryForObject() 대신 query()를 사용한다는 것이다.
즉, 결과가 여러 개일 수 있을 때는 query()를 사용해 리스트 형태로 받는다.
상품 이름에 특정 문자열이 포함된 상품을 검색하는 기능은 다음과 같이 구현할 수 있다.
public List<Product> findByNameContaining(String name){
SqlParameterSource namedParameter = new MapSqlParameterSource("name", "%" + name + "%");
List<Product> products = namedParameterJdbcTemplate.query(
"SELECT * FROM products WHERE name LIKE :name",
namedParameter,
new BeanPropertyRowMapper<>(Product.class)
);
return products;
}
여기서 % 기호는 SQL의 와일드카드다.
LIKE '%abc%'는 문자열 어딘가에 abc가 포함되어 있으면 매칭된다는 뜻이다.
즉, 이름의 앞뒤에 어떤 문자가 오든 상관없이, 중간에 해당 문자열이 포함되어 있으면 검색 대상이 된다.
이름 검색 기능도 결국 구조는 단건 조회와 크게 다르지 않다.
상품 수정
상품 수정 기능은 이전 리스트 기반 구현에서도 id를 기준으로 특정 상품을 찾은 뒤,
그 내용을 교체하는 방식으로 구현했었다.
데이터베이스를 사용할 때도 본질은 같다.
다만 이제는 자바 리스트를 직접 수정하는 대신, SQL의 UPDATE 문을 사용해 데이터베이스 안의 행을 수정하게 된다.
레포지토리 코드는 다음과 같이 작성할 수 있다.
public Product update(Product product){
SqlParameterSource namedParameter = new BeanPropertySqlParameterSource(product);
namedParameterJdbcTemplate.update(
"UPDATE products SET name = :name, price = :price, amount = :amount WHERE id = :id",
namedParameter
);
return product;
}
이 코드의 핵심은 BeanPropertySqlParameterSource(product)다.
이 객체는 product 객체 안의 필드 이름과 값을 읽어서 SQL의 이름 기반 파라미터와 자동으로 연결해준다.
:name → product.getName()
:price → product.getPrice()
:amount → product.getAmount()
:id → product.getId()
이렇게 매핑된다고 보면 된다.
이 수정 SQL은 “id가 같은 행을 찾아서, name/price/amount를 새로운 값으로 바꾼다”는 의미다.
상품 삭제
상품 삭제 기능은 CRUD 중에서도 구조가 가장 단순한 편이다.
조회는 결과를 객체로 매핑해야 하고, 수정은 바뀔 값을 여러 개 반영해야 하지만,
삭제는 특정 조건에 맞는 데이터를 제거하면 되기 때문이다.
레포지토리 코드는 다음과 같이 작성할 수 있다.
public void delete(Long id){
SqlParameterSource namedParameter = new MapSqlParameterSource("id", id);
namedParameterJdbcTemplate.update(
"DELETE FROM products WHERE id = :id",
namedParameter
);
}
이 코드에서 MapSqlParameterSource("id", id)는 SQL 안의 :id와 실제 id 값을 연결한다.
그리고 DELETE FROM products WHERE id = :id는 상품 번호가 같은 행을 찾아 삭제하는 SQL이다.
즉, 상품 삭제는 결국 상품 번호를 기준으로 특정 행 하나를 제거하는 작업이라고 볼 수 있다.
리스트 기반 구현에서는 먼저 findById(id)로 상품을 찾고, remove()로 리스트에서 제거했다.
데이터베이스 기반 구현에서는 그 과정을 SQL이 대신 수행하는 셈이다.
'공부 기록 > 이것이 백엔드 개발이다 With Java' 카테고리의 다른 글
| EP24. 상품 관리 애플리케이션에 객체지향 더하기 2편 (0) | 2026.04.26 |
|---|---|
| EP23. 상품 관리 애플리케이션에 객체지향 더하기 1편 (0) | 2026.04.25 |
| EP21. 상품 관리 애플리케이션에 데이터베이스 연동하기 2편 (0) | 2026.04.23 |
| EP20. 상품 관리 애플리케이션에 데이터베이스 연동하기 1편 (0) | 2026.04.22 |
| EP19. 상품 관리 애플리케이션에 유효성 검사 추가하기 2편 (0) | 2026.04.21 |