시작하기 전,
예전, DB 마다 커넥션을 연결하는 방법, SQL을 전달하는 방법과 그 결과를 응답 받는 방법이 모두 달랐다.
문제 → DB 가 바뀌면, 코드도 바꿔야 한다.
문제 → 개발자가 각각의 DB 사용법을 모두 공부해야 한다.
이러한 문제를 해결하기 위해 JDBC → 표준 인터페이스가 (자바 표준) 등장!
대표적으로 3가지 기능을 표준 인터페이스로 정의해서 제공한다.


→ JDBC 를 직접 사용하면 너무 복잡하다.
→ 그러면 왜 JDBC 를 배워야 할까?
: 위의 기술들 모두 JDBC를 사용한다. 따라서 직접 JDBC를 사용하지 않더라도, JDBC가 어떻게 동작하는지 기본 원리를 알아두어야 한다.
: 문제가 발생했을 때 근본적인 문제를 찾아서 해결할 수 있다.
애플리케이션과 데이터베이스를 연결해보자.
ConnectionConst
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 = "";
}
DBConnectionUtil
@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);
}
}
}
Connection → JDBC 표준 인터페이스가 제공하는 바로 그 커넥션!

애플리케이션 로직에서 커넥션이 필요하면, DriverManager.getConnection()을 호출한다.
→ URL, USERNAME, PASSWORD
DriverManager는 라이브러리에 등록된 드라이버 목록을 자동으로 인식한다.
찾은 커넥션 구현체가 애플리케이션 로직으로 반환된다.
받은 해당 DB의 커넥션 구현체를 사용하면 된다!
JDBC를 사용해서 애플리케이션을 개발해보자.
package hello.jdbc.repository;
import hello.jdbc.connection.DBConnectionUtil;
import hello.jdbc.domain.Member;
import lombok.extern.slf4j.Slf4j;
import java.sql.*;
import java.util.NoSuchElementException;
/**
* JDBC - DriverManager를 사용해서 저장해보기
*/
@Slf4j
public class MemberRepositoryV0 {
public Member save(Member member) throws SQLException {
String sql = "insert into member(member_id, money) values (?,?)";
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, member.getMemberId());
preparedStatement.setInt(2, member.getMoney());
preparedStatement.executeUpdate();
return member;
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
close(connection, preparedStatement, null);
}
}
public Member findById(String memberId) throws SQLException {
String sql = "select * from member where member_id = ?";
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, memberId);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
Member member = new Member();
member.setMemberId(resultSet.getString("member_id"));
member.setMoney(resultSet.getInt("money"));
return member;
} else {
throw new NoSuchElementException("member not found memberId = " + memberId);
}
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
close(connection, preparedStatement, resultSet);
}
}
public void update(String memberId, int money) throws SQLException {
String sql = "update member set money=? where member_id=?";
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, money);
preparedStatement.setString(2, memberId);
int resultSize = preparedStatement.executeUpdate();
log.info("resultSize={}", resultSize);
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
close(connection, preparedStatement, null);
}
}
public void delete(String memberId) {
String sql = "delete from member where member_id = ?";
Connection connection = null;
PreparedStatement preparedStatement = null;
try{
connection = getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, memberId);
preparedStatement.executeUpdate();
log.info("delete memberId={}", memberId);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
private void close(Connection connection, Statement statement, ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
log.error("error", e);
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
log.error("error", e);
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
log.error("error", e);
}
}
}
private Connection getConnection() {
return DBConnectionUtil.getConnection();
}
}
TestCode
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;
import static org.junit.jupiter.api.Assertions.*;
@Slf4j
class MemberRepositoryV0Test {
MemberRepositoryV0 repository = new MemberRepositoryV0();
@Test
void crud() throws SQLException {
Member memberV0 = new Member("memberV100", 10000);
repository.save(memberV0);
//FindById
Member findMember = repository.findById(memberV0.getMemberId());
log.info("findMember = {}", findMember);
log.info("member != findMember {}", memberV0 == findMember);
assertThat(findMember).isEqualTo(memberV0);
//update money 10000 -> 20000
repository.update(memberV0.getMemberId(), 20000);
Member updatedMember = repository.findById(memberV0.getMemberId());
assertThat(updatedMember.getMoney()).isEqualTo(20000);
//delete
repository.delete(memberV0.getMemberId());
//등록 했다가 바로 삭제하는 것이기 때문에 볼 수 없다.
//그럼 검증을 어떻게 해야 하는가?
assertThatThrownBy(() -> repository.findById(memberV0.getMemberId())).isInstanceOf(NoSuchElementException.class);
}
}
getConnection() : DBConnectionUtil 을 통해 데이터베이스 커넥션을 획득한다.