
업무를 함에 있어 가장 효율성을 극대화 시킬 수 있는 방법이 뭔줄 아는가?
명확한 목표가 있어야 한다 는 점이다.
이번 실습에 있어 나의 목표는 JDBC를 완전히 깨우친다거나, 유의미한 이슈를 발견한다던가,
는 아니고. 미션 제출일 9시에 월드컵 태국전이 있어서 놀라운 집중력으로 1시간만에 제출을 할 수 있었다. 개발이 하기 싫을 땐 이거 끝내고 집 가서 뭐할지 정해놓고 해보셈. 효과 개굿 ㄷㄷ
1.1 build.gradle 파일을 이용하여 다음 두 의존성을 추가하세요.
--build.gradle
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
...
}
1.2 데이터베이스 테이블 생성을 위해 schema.sql 파일을 생성하고 테이블을 생성하는 쿼리를 작성하세요.
--schema.sql
CREATE TABLE reservation
(
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
date VARCHAR(255) NOT NULL,
time VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
1.3
--application.properties
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:database
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void 오단계() {
try (Connection connection = jdbcTemplate.getDataSource().getConnection()) {
assertThat(connection).isNotNull();
assertThat(connection.getCatalog()).isEqualTo("DATABASE");
assertThat(connection.getMetaData().getTables(null, null, "RESERVATION", null).next()).isTrue();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
👉 데이터베이스가 도입됐으니 DAO(Repository)를 도입해야겠다!
👉 DAO의 도입에 따라 Service 코드에도 적절한 수정이 필요하겠다.
이전 실습에서는 List 객체에 임시로 데이터를 담아 List를 조회했지만 이번엔 데이터베이스에 데이터를 담고 JDBC 메소드를 이용해 데이터를 읽어올 것이다.
--QueryDAO.java
@Repository
public class QueryDAO {
// JdbcTemplate 을 사용하여 SQL 문을 실행할 수 있다.
// JdbcTemplate 은 PreparedStatement 를 생성하고 SQL 매개변수를 설정하며, ResultSet 을 처리할 수 있다.
private JdbcTemplate jdbcTemplate;
public QueryDAO(JdbcTemplate jdbcTemplate){
this.jdbcTemplate=jdbcTemplate;
}
public List<Reservation> findAllReservations() {
String sql = "SELECT id, name, date, time FROM reservation";
return jdbcTemplate.query(
sql,
(resultSet, rowNum) -> {
Reservation reservation = new Reservation(
resultSet.getLong("id"),
resultSet.getString("name"),
resultSet.getString("date"),
resultSet.getString("time")
);
return reservation;
});
}
}
--ReservationService.java
public class ReservationService {
@Autowired
private QueryDAO queryDAO; // DAO 주입
public List<Reservation> getAllReservations() {
return queryDAO.findAllReservations();
}
}
@Test
void 육단계() {
jdbcTemplate.update("INSERT INTO reservation (name, date, time)
VALUES (?, ?, ?)", "브라운", "2023-08-05", "15:40");
List<Reservation> reservations = RestAssured.given().log().all()
.when().get("/reservations")
.then().log().all()
.statusCode(200).extract()
.jsonPath().getList(".", Reservation.class);
Integer count = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class);
assertThat(reservations.size()).isEqualTo(count);
}

@Repository
public class QueryDAO {
private JdbcTemplate jdbcTemplate;
public QueryDAO(JdbcTemplate jdbcTemplate){
this.jdbcTemplate=jdbcTemplate;
}
...
public void addReservation(Reservation reservation) {
String sql = "INSERT INTO reservation(name, date, time) VALUES (?, ?, ?)";
jdbcTemplate.update(sql, reservation.getName(), reservation.getDate(), reservation.getTime());
}
public void deleteReservation(Long id){
String sql = "DELETE FROM reservation WHERE id = ?";
jdbcTemplate.update(sql, id);
}
...
}
👉 앞서 조회에는 query 메소드를 사용한 반면 추가 및 삭제에선 update 메소드를 사용한다.
👉 Native SQL을 사용하는 JDBC에서 SQL문 작성 역량은 중요하다.
--ReservationController.java
@Controller
public class ReservationController {
...
final AtomicLong index = new AtomicLong(0);
@PostMapping("/reservations")
public ResponseEntity<Void> create(@RequestBody Reservation reservation) {
reservationService.addReservation(reservation);
return ResponseEntity.created
(URI.create("/reservations/" + index.incrementAndGet())).build();
}
@DeleteMapping("/reservations/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
reservationService.deleteReservation(id);
return ResponseEntity.noContent().build();
}
...
}
@Test
void 칠단계() {
Map<String, String> params = new HashMap<>();
params.put("name", "브라운");
params.put("date", "2023-08-05");
params.put("time", "10:00");
RestAssured.given().log().all()
.contentType(ContentType.JSON)
.body(params)
.when().post("/reservations")
.then().log().all()
.statusCode(201)
.header("Location", "/reservations/1");
Integer count = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class);
assertThat(count).isEqualTo(1);
RestAssured.given().log().all()
.when().delete("/reservations/1")
.then().log().all()
.statusCode(204);
Integer countAfterDelete = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class);
assertThat(countAfterDelete).isEqualTo(0);
}
