[Java Spring 무작정 따라하기] JDBC

khj·2024년 8월 1일
post-thumbnail

💡 JDBC란?

JDBC(Java Database Connectivity)는 자바 애플리케이션에서 DB에 접속하고 쿼리를 실행할 수 있도록하는 표준 API이다.
강의에서는 매우 오래되고 복잡한 방법이라고 설명하고 있다.
그래도 일단 구현을 해보고 다시 JPA로 교체하는 방식으로 진행해 보려고 한다.
DB는 강의와 동일하게 H2를 사용했다.

✨ JDBC 설정 추가

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 리포지토리 생성

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 리포지토리 코드

다음 코드는 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);
    }
}
profile
Spring, Django 개발 블로그

0개의 댓글