You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
JdbcTemplate은 spring-jdbc 라이브러리에 포함되어 있는데, 이 라이브러리는 스프링으로 jDBC를 사용할 때 기본으로 사용되는 라이브러리이다. 그리고 별도의 복잡한 설정 없이 바로 사용이 가능하다.
반복 문제 해결(코드측면에서)
JdbcTemplate은 템플릿 콜백 패턴을 사용해서, JDBC를 직접 사용할 때 발생하는 대부분의 반복 작업을 처리해준다.
개발자는 SQL을 작성하고, 전달할 파리미터를 정의하고, 응답 값을 매핑하기만 하면 된다.
우리가 생각할 수 있는 대부분의 반복 작업을 대신 처리해준다.
커넥션 획득
statement 를 준비하고 실행
결과를 반복하도록 루프를 실행
커넥션 종료, statement , resultset 종료
트랜잭션 다루기 위한 커넥션 동기화
예외 발생시 스프링 예외 변환기 실행
✅ 단점
동적 SQL을 해결하기 어렵다.
✅ JdbcTemplate 설정
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
//JdbcTemplate 추가
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
//H2 데이터베이스 추가
runtimeOnly 'com.h2database:h2'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//테스트에서 lombok 사용
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}
추가된 부분
//JdbcTemplate 추가
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
//H2 데이터베이스 추가
runtimeOnly 'com.h2database:h2'
2️⃣ JdbcTemplate 적용 1 - 기본
Jdbc Template를 이용해서 데이터베이스에 저장해보자.
ItemRepository 인터페이스가 있으니 이 인터페이스를 기반으로 JdbcTemplate을 사용하는 새로운 구현체를 개발
JdbcTemplateItemRepositoryV1
/** * JdbcTemplate */@Slf4jpublicclassJdbcTemplateItemRepositoryV1implementsItemRepository {
privateJdbcTemplatetemplate;
// dataSource를 의존 관계 주입 받고 생성자 내부에서 JdbcTemplate을 생성한다. // 스프링에서는 JdbcTemplte을 사용할 때 관계상 이 방법을 많이 사용 // 참고 : JdbcTemplate을 스프링 빈으로 직접 등록하고 주입 받아도되긴함 publicJdbcTemplateItemRepositoryV1(DataSourcedataSource) {
this.template = newJdbcTemplate(dataSource); // JdbcTemplate은 데이터소스(dataSource)가 필요
}
@OverridepublicItemsave(Itemitem) {
Stringsql = "insert into item (item_name, price, quantity) values (?, ?, ?)";
//데이터를 저장할 때 PK 생성에 identity(auto incrrement) 방식을 사용하기 때문에, PK인 ID 값을 DB에서 자동으로 생성해준다.//따라서 PK ID 값은 데이터베이스가 생성하기 때문에 데이터베이스에 INSERT가 완료되는 시점에 PK ID값을 확인할 수 있음KeyHolderkeyHolder = newGeneratedKeyHolder();
//template.update()는 데이터 변경할 때는 update()를 사용하면된다. // INSERT, UPDATE, DELETE SQL에 사용한다.template.update(connection -> {
//자동 증가 키PreparedStatementps = connection.prepareStatement(sql, newString[] {"id"});
ps.setString(1, item.getItemName());
ps.setInt(2, item.getPrice());
ps.setInt(3, item.getQuantity());
returnps;
}, keyHolder);
longkey = keyHolder.getKey().longValue();
item.setId(key);
returnitem;
}
@Overridepublicvoidupdate(LongitemId, ItemUpdateDtoupdateParam) {
Stringsql = "update item set item_name=?, price=?, quantity=? where id=?";
// 데이터변경은 template.update() 사용 // ? 에 바인딩할 때 파라미터 순서대로 전달 (순서조심)template.update(sql,
updateParam.getItemName(),
updateParam.getPrice(),
updateParam.getQuantity(),
itemId);
//반환값은 해당 쿼리의 영향을 받은 row 수이다. 여기서는 where id =?를 지정했기 때문에 영향 받은 row수는 최대 1개이다.
}
@OverridepublicOptional<Item> findById(Longid) { // 인터페이스는 결과가 없을 때 Optional을 반환해야 한다. 따라서 결과가 없으면 예외를 잡아서 Optional.empty를 대신 반환한다.Stringsql = "select id, item_name, price, quantity from item where id = ?";
try {
//template.queryForObject() - 결과 로우가 하나일 때 사용한다.//RowMapper는 데이터베이스의 반환 결과인 ResultSet을 객체로 변환한다. Itemitem = template.queryForObject(sql, itemRowMapper(), id);
returnOptional.of(item);
// 결과가 없으면 EmptyResultDataAccessException 예외가 발생// 결과가 둘 이상이면 IncorrectResultSizeDataAccessException 예외 발생
} catch (EmptyResultDataAccessExceptione) {
returnOptional.empty();
}
}
@OverridepublicList<Item> findAll(ItemSearchCondcond) {
StringitemName = cond.getItemName();
IntegermaxPrice = cond.getMaxPrice();
Stringsql = "select id, item_name, price, quantity from item";
//동적 쿼리if (StringUtils.hasText(itemName) || maxPrice != null) {
sql += " where";
}
booleanandFlag = false;
List<Object> param = newArrayList<>();
if (StringUtils.hasText(itemName)) {
sql += " item_name like concat('%',?,'%')";
param.add(itemName);
andFlag = true;
}
if (maxPrice != null) {
if (andFlag) {
sql += " and";
}
sql += " price <= ?";
param.add(maxPrice);
}
log.info("sql={}", sql);
//template.query() - 결과가 하나 이상일 때 사용//RowMapper는 데이터베이스의 반환 결과인 ResultSet을 객체로 변환한다.//결과가 없으면 빈 컬렉션을 반환한다.returntemplate.query(sql, itemRowMapper(), param.toArray());
}
//itemRowMapper() - 데이터베이스의 조회 결과를 객체로 변환할 때 사용한다. //JDBC를 직접 사용할 때 ResultSet를 사용했던 부분을 떠올리면 된다. privateRowMapper<Item> itemRowMapper() {
return (rs, rowNum) -> {
Itemitem = newItem();
item.setId(rs.getLong("id"));
item.setItemName(rs.getString("item_name"));
item.setPrice(rs.getInt("price"));
item.setQuantity(rs.getInt("quantity"));
returnitem;
};
}
}
3️⃣ JdbcTemplate 적용 2 - 동적 쿼리 문제
결과를 검색하는 findAll() 에서 어려운 부분은 사용자가 검색하는 값에 따라서 실행하는 SQL이 동적으로 달라져야한다는 점.
✅ 예시)
검색 조건이 없음
select id, item_name, price, quantity
from item
상품명(itemName)으로 검색
select id, item_name, price, quantity
from item
where item_name like concat('%', ?, '%')
최대 가격(maxPrice)으로 검색
select id, item_name, price, quantity
from item
where price <= ?
상품명(itemName), 최대 가격(maxPrice)둘다 검색
select id, item_name, price, quantity
from item
where item_name like concat('%', ?, '%')
and price <= ?
4가지 상황에 따른 SQL을 동적으로 생성해야한다. 동적 쿼리가 언듯 보면 쉬워보이지만, 막상 개발해보면 생각보다 다양한 상황을 고려해야 한다.
예를들면 어떤 경우에는 where를 앞에 넣고 어떤 경우에는 and를 넣어야 하는지 등을 모두 계산해야 한다. 그리고 각 상황에 맞추어 파라미터도 생성해야 한다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
데이터 접근 기술 - 스프링 JdbcTemplate
1️⃣ JdbcTemplate 소개와 설정
✅JdbcTemplate 장점
✅ 단점
✅ JdbcTemplate 설정
추가된 부분
2️⃣ JdbcTemplate 적용 1 - 기본
ItemRepository 인터페이스가 있으니 이 인터페이스를 기반으로 JdbcTemplate을 사용하는 새로운 구현체를 개발
3️⃣ JdbcTemplate 적용 2 - 동적 쿼리 문제
✅ 예시)
4️⃣ JdbcTemplate 적용 3 - 구성과 실행
ItemRepository구현체로 JdbcTemplateItemRepositoryV1이 사용되도록 했다. 이제 메모리 저장소 가 아니라 실제 DB에 연결하는 JdbcTemplate이 사용된다.
ItemServiceApplication - 변경
✅ 데이터베이스 접근 설정
DataSource, 트랜잭션 매니저를 스프링 빈으로 자동 등록한다.✅ 실행
http://localhost:8080✅ 로그 추가
application.properties에 다음을 추가하면 된다.main,test설정이 분리되어 있기 때문에 둘다 확인하려면 두 곳에 모두 추가해야 한다.All reactions