
JDBC(Java Database Connectivity)는 자바 애플리케이션에서 DB에 접속하고 쿼리를 실행할 수 있도록하는 표준 API이다.
강의에서는 매우 오래되고 복잡한 방법이라고 설명하고 있다.
그래도 일단 구현을 해보고 다시 JPA로 교체하는 방식으로 진행해 보려고 한다.
DB는 강의와 동일하게 H2를 사용했다.
JDBC와 H2를 사용하기 위해서는 먼저 build.gradle 파일에 라이브러리를 추가해주어야 한다.
// build.gradle
...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
}
...
그리고 DB와 연결하기 위한 application.properties 파일을 작성한다.
# application.properties
spring.application.name=hello-spring
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
username과 password는 수정하지 않고 기본설정으로 사용했다.
JDBC를 사용해서 데이터를 저장하기 위한 리포지토리 파일도 생성했다.
코드가 너무 길어서 전체 코드는 글의 마지막에 첨부하고 save 부분만 가져와 봤다.
// repository/JdbcMemberRepository.java
...
public class JdbcMemberRepository implements MemberRepository {
private final DataSource dataSource;
public JdbcMemberRepository(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Member save(Member member) {
String sql = "insert into member(name) values(?)";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, member.getName());
pstmt.executeUpdate();
rs = pstmt.getGeneratedKeys();
if (rs.next()) {
member.setId(rs.getLong(1));
} else {
throw new SQLException("id 조회 실패");
}
return member;
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
...
}
먼저 getConnection()을 통해 DB에 연결하고 prepareStatement 객체를 생성해 반환되는 키를 받도록 한다.
setString으로 SQL 쿼리의 첫 번째 인자를 member의 name값으로 설정해주고 executeUpdate()로 쿼리를 실행한다.
그리고 작성한 리포지토리를 사용하도록 SpringConfig의 memberRepository부분을 수정해주었다.
...
import hello.hello_spring.repository.JdbcMemberRepository;
@Configuration
public class SpringConfig {
...
@Bean
public MemberRepository memberRepository(){
return new JdbcMemberRepository(dataSource);
}
}
코드를 작성했으니 테스트를 해봤다.
회원 등록 페이지에서 spring123, spring135, java_spring으로 3번의 회원 등록을 진행했다.

회원 목록 페이지에선 위와 같이 출력되었다.
하지만 이 페이지만 확인해서는 DB가 연결되었는지 확인할 수 없으니 H2 콘솔 화면에서 SELECT문을 실행시켜봤다.

회원 등록한 name값들이 잘 저장되어 있는 것을 확인할 수 있었다.
다음 코드는 JDBC를 사용하기 위한 리포지토리 코드이다.
// repository/JdbcMemberRepository
package hello.hello_spring.repository;
import hello.hello_spring.domain.Member;
import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class JdbcMemberRepository implements MemberRepository {
private final DataSource dataSource;
public JdbcMemberRepository(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Member save(Member member) {
String sql = "insert into member(name) values(?)";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, member.getName());
pstmt.executeUpdate();
rs = pstmt.getGeneratedKeys();
if (rs.next()) {
member.setId(rs.getLong(1));
} else {
throw new SQLException("id 조회 실패");
}
return member;
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
@Override
public Optional<Member> findById(Long id) {
String sql = "select * from member where id = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setLong(1, id);
rs = pstmt.executeQuery();
if(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return Optional.of(member);
} else {
return Optional.empty();
}
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
@Override
public List<Member> findAll() {
String sql = "select * from member";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
List<Member> members = new ArrayList<>();
while(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
members.add(member);
}
return members;
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
@Override
public Optional<Member> findByName(String name) {
String sql = "select * from member where name = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name);
rs = pstmt.executeQuery();
if(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return Optional.of(member);
}
return Optional.empty();
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
private Connection getConnection() {
return DataSourceUtils.getConnection(dataSource);
}
private void close(Connection conn, PreparedStatement pstmt, ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (pstmt != null) {
pstmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null) {
close(conn);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void close(Connection conn) throws SQLException {
DataSourceUtils.releaseConnection(conn, dataSource);
}
}