JDBC(Java Database Connectivity)는 자바가 여러 DB와 통신하기 위한 표준 API이고, Hibernate·MyBatis·스프링 JDBC 모두 그 위에 있다. JdbcTemplate은 스프링이 JDBC의 반복 작업(연결 열고 닫기, 예외 변환, 결과 순회)을 대신해 주는 클래스다.
순수 JDBC가 번거로운 이유
드라이버 로드 → Connection 얻기 → Statement 준비 → 실행
→ ResultSet 순회 → 예외 처리 → ResultSet·Statement·Connection 닫기매 쿼리마다 이 보일러플레이트를 쓰고, 체크 예외(checked exception)를 직접 처리하고, 닫는 것을 깜빡하면 연결이 샌다. SQL에 DB 방언(dialect)이 섞이면(MySQL LIMIT vs Oracle FETCH FIRST) DB를 바꿀 때 전부 고쳐야 한다.
JdbcTemplate이 맡는 것
개발자는 SQL, 파라미터, 행 하나를 객체로 바꾸는 방법만 정한다. 연결 관리, 실행, 순회, 예외 변환(DataAccessException), 트랜잭션 참여, 자원 정리는 스프링이 한다. 아래 query(sql, rowMapper, args...)에서 람다 (rs, rowNum) -> ...가 RowMapper이고, "OPEN"이 ? 자리에 들어간다.
public List<Contact> findOpen() {
return jdbc.query("SELECT id, name, status FROM contact WHERE status = ?",
(rs, rowNum) -> new Contact(rs.getLong("id"), rs.getString("name"), rs.getString("status")),
"OPEN");
}
int updated = named.update(
"UPDATE contact SET status = :status WHERE id = :id",
Map.of("status", "CLOSED", "id", id));- RowMapper: ResultSet의 한 행을 객체로 바꾸는 함수. 컬럼명과 필드명이 같으면
BeanPropertyRowMapper나DataClassRowMapper를 쓴다 - NamedParameterJdbcTemplate:
?대신:이름자리표시자. 파라미터가 많을 때 순서 실수를 막는다 - 파라미터 바인딩은 SQL 주입(SQL injection)을 막는다. 문자열 결합으로 SQL을 만들지 않는다
- 스레드 안전해서 빈 하나를 여러 DAO(Data Access Object)가 공유한다. 스프링 부트는
DataSource와 함께 자동으로 만든다 - 스프링 6.1부터는 플루언트 API인
JdbcClient도 있다(2026 기준)
H2
자바로 만든 인메모리 DB라 테스트·PoC(Proof of Concept)에 쓴다. 스프링 부트는 클래스패스에 H2가 있으면 자동으로 연결하고, schema.sql·data.sql로 시작 시 테이블과 데이터를 만든다. 재시작하면 데이터가 사라지고 방언이 운영 DB와 달라, 운영과 같은 DB를 컨테이너로 띄우는 테스트(Testcontainers)가 더 믿을 만하다.
H2 웹 콘솔 (Spring Boot 3.5 기준)
브라우저에서 테이블을 보는 콘솔이다. DevTools를 쓰면 자동으로 켜지고, 아니면 spring.h2.console.enabled=true로 켠다. 경로는 기본 /h2-console이고 spring.h2.console.path로 바꾼다. 스프링 부트 4부터는 spring-boot-h2console 의존성도 있어야 한다(2026 기준).
spring.h2.console.enabled=true
# 기본값 true면 DB 이름이 실행마다 무작위로 정해진다
spring.datasource.generate-unique-name=false
# 부트가 만드는 URL: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.name=testdb- 계정을 따로 정하지 않으면 부트는 내장 DB에 사용자
sa, 빈 비밀번호를 쓴다 - 부트는 기본으로 DB 이름을 무작위로 만든다. 콘솔에 넣을 JDBC URL을 고정하려면 위처럼
generate-unique-name=false로 끈다. 이때 이름을 안 주면testdb가 된다
스프링 시큐리티를 쓰면 콘솔용 설정을 더 해야 한다. 콘솔은 프레임으로 화면을 그리고 CSRF 방어를 하지 않기 때문이다. 콘솔 요청에만 CSRF 검사를 끄고, 응답의 X-Frame-Options를 SAMEORIGIN으로 둬야 한다. 부트 문서는 콘솔 경로 전용 필터 체인을 따로 두는 방법을 보여 준다. PathRequest.toH2Console()은 경로를 바꿔도 맞는 경로를 가리킨다.
@Profile("dev")
@Configuration(proxyBeanMethods = false)
public class DevH2ConsoleSecurityConfig {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain h2ConsoleSecurityFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher(PathRequest.toH2Console());
// 부트 문서는 이 자리를 yourCustomAuthorization()으로 비워 둔다. 여기서는 개발용이라 모두 허용했다
http.authorizeHttpRequests((auth) -> auth.anyRequest().permitAll());
http.csrf(CsrfConfigurer::disable);
http.headers((headers) -> headers.frameOptions(FrameOptionsConfig::sameOrigin));
return http.build();
}
}콘솔은 개발용이다. 운영에서 CSRF 방어를 끄거나 프레임을 허용하면 보안 위험이 생기므로 @Profile("dev")처럼 개발 환경에만 둔다.
SQL을 직접 쓰지 않고 객체로 다루는 다음 단계는 Spring Data 리포지터리와 쿼리 메서드와 JPA다. 클래스를 테이블에 대응시키는 방법은 JPA 엔티티 기본 매핑에 있다. 오라클 저장 프로시저 호출은 Oracle PL/SQL을 본다.
출처: Spring Framework 문서: JdbcTemplate · NamedParameterJdbcTemplate · JdbcClient · Spring Boot 3.5 문서: H2 웹 콘솔 · 보안 애플리케이션에서 H2 콘솔 쓰기 · spring.datasource.generate-unique-name · DataSourceProperties 소스: 기본 계정 · EmbeddedDatabaseConnection 소스: H2 URL · Spring Boot 4 문서: H2 웹 콘솔 · X-Frame-Options