BackEnd/Database

데이터베이스 연결, JDBC개발 - 등록, 조회, 수정 ,삭제

연향동큰손 2025. 1. 12. 15:36

서버와 데이터베이스를 연결하는 방법에 대해서 공부했다.

 

사용된 데이터베이스 : H2

 

 

 


 

데이터베이스에 접근하기위해 필요한 정보들을 상수로 만들어 관리

package hello.jdbc.connection;

public abstract class ConnectionConst {
    public static final String URL = "jdbc:h2:tcp://localhost/~/test";
    public static final String USERNAME = "sa";
    public static final String PASSWORD = "";
}

 

 

 

데이터베이스에 연결하려면 JDBC가 제공하는 DriverManager.getConnection(..) 을 사용하면 된다.

이렇게 하면 라이브러리에서 데이터베이스 드라이버를 찾아서 해당 드라이버가 제공하는 커넥션을 반환해준다.

package hello.jdbc.connection;

import lombok.extern.slf4j.Slf4j;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import static hello.jdbc.connection.ConnectionConst.*;

@Slf4j
public class DBConnectionUtil {
    public static Connection getConnection(){
        try {
            Connection connection = DriverManager.getConnection(URL,USERNAME,PASSWORD);
            log.info("get connection={}, class={}",connection,connection.getClass());
            return connection;
        } catch (SQLException e) {
           throw new IllegalStateException(e);
        }


    }
}

 

 

JDBC DriverManager

 

 

JDBC가 제공하는 DriverManager는 라이브러리에 등록된 DB 드라이버들을 관리하고, 커넥션을 획득하는 기능을 제공한다. 

 

DB커넥션과 관련된 URL을 체크하여 URL이 jdbc:h2로 시작하면 H2드라이버가 데이터베이스에 연결해서 커넥션을 획득한다.

만약 jdbc:mysql이면 MySQL드라이버가 해당 커넥션을 획득하는 방식이다.

 

JDBC개발 - 등록

 

package hello.jdbc.repository;

import hello.jdbc.connection.DBConnectionUtil;
import hello.jdbc.domain.Member;
import lombok.extern.slf4j.Slf4j;

import java.sql.*;

import static hello.jdbc.connection.DBConnectionUtil.getConnection;

@Slf4j
public class MemberRepositoryV0 {

    public Member save(Member member) throws SQLException {
        String sql = "insert into member(member_id,money) values(?,?)"; //쿼리문 직접 작성

        Connection con =null;
        PreparedStatement pstmt = null;

        try {
            con = getConnection();
            pstmt = con.prepareStatement(sql);
            pstmt.setString(1,member.getMemberId());
            pstmt.setInt(2,member.getMoney());
            pstmt.executeUpdate(); //Statement를 통해 SQL커넥션을 이용하여 실제 데이터베이스에 전달한다.
            return member;
        }catch (SQLException e){
            log.error("db error",e);
            throw e;
        }finally {
            close(con,pstmt,null);
        }
    }
    private void close(Connection con, Statement stmt, ResultSet rs) throws SQLException {
        if(rs!=null){
            try {
               rs.close();
            }catch (SQLException e){
                log.info("error",e);
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            }catch (SQLException e){
                log.info("error",e);
            }

        }
        if(con!=null) {
           try {
               con.close();
           }catch (SQLException e){
               log.info("error",e);
           }
        }
    }
    private Connection getConnection() { //DBConnectionUtil클래스의 DB 커넥션 메서드 활용
        return DBConnectionUtil.getConnection();
    }

}

 

con.prepareStatement(sql) : 데이터베이스에 전달할 SQL과 파라미터로 전달할 데이터들을 준비한다. 

 

pstmt.setString(1, member.getMemberId()) ==> SQL의 첫번째 ? 에 값을 지정한다.

pstmt.setInt(2, member.getMoney()) ==> SQL의 두번째 ? 에 값을 지정한다.

 

*주의*

쿼리를 실행하고 나서 Connection과 PreparedStatement를 정리 해줘야 한다.

정리 해주지 않으면 커넥션이 끊어지지 않고 계속 유지가 되어서 문제가 발생할 수 있다.

 

 

<테스트 코드>

package hello.jdbc.repository;

import hello.jdbc.domain.Member;
import org.junit.jupiter.api.Test;

import java.sql.SQLException;



class MemberRepositoryV0Test {
    MemberRepositoryV0 repository = new MemberRepositoryV0();

    @Test
    void crud() throws SQLException {
       Member member=new Member("memberV0",10000);
        repository.save(member);
    }

}

 

실행 결과

 

 

조회
public Member findById(String memberId) throws SQLException {
    String sql = "select * from member where member_id = ?";

    Connection con = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;

    try{
        con = getConnection();
        pstmt = con.prepareStatement(sql);
        pstmt.setString(1,memberId);
        rs=pstmt.executeQuery();
        if(rs.next()){
            Member member = new Member();
            member.setMemberId(rs.getString("member_id"));
            member.setMoney(rs.getInt("money"));
            return member;
        }else{
            throw new NoSuchElementException("member not fond memberId="+memberId);
        }
    }catch (SQLException e){
        log.error("db error",e);
        throw e;
    }finally {
        close(con,pstmt,rs);
    }
}

sql : 데이터 조회를 위한 select SQL을 준비한다.

rs = pstmt.executeQuery() 데이터를 조회 할 때는 executeQuery() 데이터를 변경할 때는 를 사용한다. 

데이터를 변경할때는 executeUpdate() 를 사용한다.

 

rs.next() : resultSet에서 최초의 커서는 아무것도 가리키고 있지 않기 때문에 rs.next()를 한번 호출 해줘야 한다.

 

rs.next() 가 true이면 ==> 커서 이동결과 데이터가 있다는 뜻

rs.next()가 false이면 ==> 커서 이동결과 데이터가 없다는 뜻

 

 

 

<테스트 코드>

@Test
void crud() throws SQLException {
   Member member=new Member("memberV2",10000);
    repository.save(member);

    //findById
    Member findMember = repository.findById(member.getMemberId());
    log.info("findMember={}",findMember);
    Assertions.assertThat(findMember).isEqualTo(member);
}

 

실행결과

 

 

수정
public void update(String memberId, int money) throws SQLException {
    String sql = "update member set money=? where member_id=?";

    Connection con = null;
    PreparedStatement pstmt = null;

    try {
        con = getConnection();
        pstmt = con.prepareStatement(sql);
        pstmt.setInt(1, money);
        pstmt.setString(2, memberId);
        int resultSize = pstmt.executeUpdate();
        log.info("resultSize={}", resultSize);
    }catch (SQLException e){
        log.error("db error", e);
        throw e;
    }finally {
        close(con, pstmt, null);
    }
}

 

 

삭제

 

public void delete(String memberId) throws SQLException{
    String sql = "delete from member where member_id=?";
    Connection con = null;
    PreparedStatement pstmt = null;
    try {
        con = getConnection();
        pstmt = con.prepareStatement(sql);
        pstmt.setString(1, memberId);

        pstmt.executeUpdate();

    }catch (SQLException e) {
        log.error("db error", e);
        throw e;
    }finally {
            close(con, pstmt, null);
    }
}

 

 

<테스트 코드>

package hello.jdbc.repository;

import hello.jdbc.domain.Member;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

import java.sql.SQLException;
import java.util.NoSuchElementException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;


@Slf4j
class MemberRepositoryV0Test {
    MemberRepositoryV0 repository = new MemberRepositoryV0();

    @Test
    void crud() throws SQLException {
       Member member=new Member("memberV4",10000);
        repository.save(member);

        //findById
        Member findMember = repository.findById(member.getMemberId());
        log.info("findMember={}",findMember);
        assertThat(findMember).isEqualTo(member);

        //update: money: 10000 -> 20000
        repository.update(member.getMemberId(), 20000);
        Member updatedMember = repository.findById(member.getMemberId());
        assertThat(updatedMember.getMoney()).isEqualTo(20000);

        //delete
        repository.delete(member.getMemberId());
        assertThatThrownBy(() -> repository.findById(member.getMemberId()))
                .isInstanceOf(NoSuchElementException.class);
    }

}

 

 

<테스트 결과>

'BackEnd > Database' 카테고리의 다른 글

스프링 예외 추상화  (0) 2025.02.04
TransactionTemplate  (0) 2025.02.01
DB 락  (0) 2025.01.19
커넥션 풀 / DataSource  (0) 2025.01.13
JDBC란 무엇인가  (0) 2025.01.11